gpt4 book ai didi

haskell - 使用 Haskell 状态 monad 有代码味道吗?

转载 作者:行者123 更新时间:2023-12-02 09:27:22 32 4
gpt4 key购买 nike

天哪,我讨厌“代码味道”这个词,但我想不出更准确的词了。

我正在设计一种高级语言和编译器 Whitespace在业余时间学习编译器构建、语言设计和函数式编程(编译器是用 Haskell 编写的)。

在编译器的代码生成阶段,我必须在遍历语法树时维护“状态”数据。例如,在编译流程控制语句时,我需要为要跳转到的标签生成唯一名称(从传入、更新和返回的计数器生成的标签,并且绝不能再次使用计数器的旧值)。另一个例子是,当我在语法树中遇到内联字符串文字时,它们需要永久转换为堆变量(在空白中,字符串最好存储在堆上)。我目前正在将整个代码生成模块包装在状态 monad 中来处理这个问题。

有人告诉我,编写编译器是一个非常适合函数范式的问题,但我发现我的设计方式与用 C 语言设计它的方式大致相同(你真的可以用任何语言编写 C 语言)语言 - 甚至带有状态单子(monad)的 Haskell)。

我想学习如何在 Haskell 中思考(而不是在函数范式中),而不是使用 Haskell 语法的 C 语言。我真的应该尝试消除/最小化状态单子(monad)的使用,还是它是一个合法的功能“设计模式”?

最佳答案

我已经用 Haskell 编写了多个编译器,状态 monad 是许多编译器问题的合理解决方案。但你想让它保持抽象——不要让人明显地看出你正在使用 monad。

这是来自 Glasgow Haskell 编译器的示例(我不是编写的;我只是围绕一些边缘进行工作),我们在其中构建控制流图。以下是制作图表的基本方法:

empyGraph    :: Graph
mkLabel :: Label -> Graph
mkAssignment :: Assignment -> Graph -- modify a register or memory
mkTransfer :: ControlTransfer -> Graph -- any control transfer
(<*>) :: Graph -> Graph -> Graph

但正如您所发现的,维护唯一标签的供应充其量是乏味的,因此我们还提供了这些功能:

withFreshLabel :: (Label -> Graph) -> Graph
mkIfThenElse :: (Label -> Label -> Graph) -- branch condition
-> Graph -- code in the 'then' branch
-> Graph -- code in the 'else' branch
-> Graph -- resulting if-then-else construct

整个Graph事物是一个抽象类型,翻译者只是以纯函数的方式愉快地构造图,而不知道任何单子(monad)正在发生。然后,当最终构建图时,为了将其转换为我们可以生成代码的代数数据类型,我们为其提供唯一标签,运行状态 monad,并提取数据结构。

状态单子(monad)隐藏在下面;虽然它没有暴露给客户端,但是Graph的定义是这样的:

type Graph = RealGraph -> [Label] -> (RealGraph, [Label])

或者更准确一点

type Graph = RealGraph -> State [Label] RealGraph
-- a Graph is a monadic function from a successor RealGraph to a new RealGraph

状态单子(monad)隐藏在抽象层后面,一点也不臭!

关于haskell - 使用 Haskell 状态 monad 有代码味道吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/607830/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com