繁体   English   中英

Haskell:除了monad之外,“do”符号对于上下文有用吗?

[英]Haskell: Would “do” notation be useful for contexts other than monads?

我们都喜欢do ,我很好奇,如果这种替代语法在理论上可能在monad世界之外有用。 如果是这样,它会简化哪些其他类型的计算? 例如,为Applicative提供相同的东西是否有意义?

我的感觉是许多Haskell程序员根本不喜欢do ,并且当你不需要Monad的全部功能时,支持使用Applicative一个常见论点是组合器<$><*>等允许非常清晰简洁的编码风格。

即使是一元的代码,很多人喜欢使用=<<明确,而不是do记号。 camccann 对你之前关于<*>问题回答给出了这个偏好的奇妙论据。

我倾向于使用do编写我的第一个草稿,然后在我修改时用组合器替换。 这只是我自己的(中)的经验和品味的问题:通常最容易为我勾画的事情了更迫切的方式(这是更方便do ),但我觉得非do代码通常是漂亮。

对于箭头,在另一方面,我不能没有使用想象proc命令do 元组刚刚变得如此丑陋。

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

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

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

通常你可能会提取这样的子表达式并将它们放在where子句或其他东西中,但是由于普通值与函数应用程序形成一个monad (>>=) - 也就是Identity monad - 你可以想象写下这样一个函数一个do阻止相反,尽管人们可能会看着你笑。


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

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

事实上,同样的总的原则是从的“成语支架”符号的真正Applicative纸:在哪里do块使用新行的Elid到一元结构,成语支架利用并列提起的Elid功能应用。 Arrowproc符号也类似,其他概念也可以用这种方式干净地表达,例如:

  • 组合数据结构,例如合并某种类型的结果集,省略合并功能
  • 其他函数应用程序习惯用法,例如参数优先“前向管道”样式,忽略了应用程序运算符
  • 并行计算,省略结果聚合函数

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

do记号基本上是说:“根据需要转化为lambda表达式和分发的方式>>=字里行间”。

当显而易见的是什么运算符用于推动所有事情时,省略并利用“换行符”运算符是很好的。

可编程换行将是处理材料列表,应用链等的好方法。 要制作列表,您还需要一个“可编程的外部”。 实际上,您可以只取三个有意义的位并使它们全部可重载:

  • 开始do
  • 在两者之间do
  • 结束do

然后,你可能不应该把它do了。 也许它应该只是一个支架。

成语括号构成了考虑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

但是,词汇范围规则有点令人不安。

Applicative有(更有限,更紧凑)成语括号,请参阅应用程序编程与效果 ,第4页。我相信Conor McBride的Strathclyde Haskell环境实现了这些。

我不知道如何推广这些特殊的语法,但也许我没有给它足够的思考。

BlazeHtml使用do -notation实际上它只是一个Monoid (虽然包裹为Monad以便能够使用do )。

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

如果你看看我的游戏“保卫国王”的代码,那么我也做了很多mconcat ,就像BlazeHtml一样,我会受益于一个漂亮的语法。

还有适合有单子的推广do记号-参数化的单子。 通过sigfpe查看Beyond Monads。 用法示例:

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

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

GHC中有一个预处理器可以为Arrows做到这一点: http//www.haskell.org/ghc/docs/6.12.2/html/users_guide/arrow-notation.html

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM