时间:2010-07-26 15:17:35

标签: syntax haskell

8 个答案:

答案 0 :(得分:13)

答案 1 :(得分:9)

关于do符号本身,它可能有助于考虑实际的优点。正如特拉维斯·布朗所指出的那样,我之前曾主张使用带有Monad和相关类型的“函数应用程序”样式,但也有另一面:有些表达式根本无法使用以直接的功能应用风格写得干净利落。例如,以下内容可以迅速使应用风格笨拙:

  • 在不同嵌套深度的多个子表达中使用的中间结果
  • 深度嵌套在子表达式中的最外层函数的参数
  • 尴尬或不一致的参数顺序,即需要将函数部分应用于第一个参数以外的其他内容
  • 基于中间结果的深度嵌入式流控制,分支之间使用共享子表达式
  • 对中间结果进行模式匹配,特别是在提取部分结果的情况下,使用它进行进一步计算,然后将修改后的版本重建为下一个结果

将这样的函数编写为单个表达式通常需要多个嵌套的lambdas,或者是一种荒谬的混淆废话,它使无点样式成为坏名称。另一方面,do块提供语法糖,以便使用嵌入式控制流轻松嵌套中间结果的范围。

通常你可能会提取这样的子表达式并将它们放在where子句中,但是因为普通值形成了一个monad,其函数应用为(>>=) - 即Identity monad - 你可以想象在do块中编写这样的函数,尽管人们可能会看着你很有趣。


除了作用域/绑定之外,do块为你做的另一件事就是将子表达式链接在一起的运算符。想象一下“在这个块中使用这个函数组合这些表达式”然后让编译器填入空白的其他情况并不难。

在简单的情况下,表达式都具有相同的类型,将它们放在列表中然后折叠它也很有效 - 使用unwordsunlines以这种方式构建字符串。 do的好处是它将表达式与通用结构和兼容(但不完全相同)类型相结合。

事实上,同样的一般原则也适用于Applicative论文中的“成语括号”符号:do块使用换行符来消除monadic构造,成语括号使用并列来消除提升函数应用。 proc的{​​{1}}符号也类似,其他概念也可以用这种方式清晰表达,例如:

  • 撰写数据结构,例如合并某种结果集,省略合并功能
  • 其他功能应用习语,例如参数优先“前向管道”样式,不再是应用程序运营商
  • 并行计算,省略结果聚合函数

虽然将这些中的许多变成单个类型或完整的Arrow实例并不太难,但为一般概念提供统一的,可扩展的语法糖可能会很好。当然有一个共同的线索将所有这些和更多的东西捆绑在一起,但这是一个与语法无关的更大的话题......

答案 2 :(得分:7)

答案 3 :(得分:5)

成语括号构成了一种考虑Applicatives的好方法,但它们并不是唯一可能的语法扩展。

菲利普·考德罗伊(Philippa Cowderoy)向哈斯克咖啡馆(Haskell-cafe)发布了一条"Applicative do"符号的提议,但观察到的任何功能看起来都像:

foo = do
    x <- bar
    y <- baz
    quux y 1234 x

其中<-绑定的变量只出现在最后一行可以使用Applicative实现 - 我实际上在方案中为此实现了一个基于语法规则的宏,我称之为'ado'。

这对于应用效果的顺序与“自然顺序”不同并且假设Haskell中存在'ado'只是出于以下情况的情况很有用:

foo = (\x y -> quux y 1234 x) <*> bar <*> baz

然而,词汇范围规则有点令人不安。

答案 4 :(得分:3)

答案 5 :(得分:3)

BlazeHtml正在使用do - 表示实际上它只是Monoid(虽然包装为Monad以便能够使用do)。< / p>

因此Monoid s的类似符号在那里很有用。

如果你看一下我的游戏"Defend The King"的代码,那么我也会做很多mconcat,就像BlazeHtml一样,我会从一个漂亮的语法中受益。

答案 6 :(得分:2)

对monad的推广符合do符号 - 参数化monad。请参阅sigfpe的Beyond Monads。用法示例:

test1' = do put 1
            x <- get
            put (show x)
            y <- get
            return (x,y)

这是一个“状态monad”,它首先存储一个数字,然后是一个字符串。

答案 7 :(得分:1)