[英]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
的另一件事就是将子表达式链接在一起的运算符。 想象一下“在这个块中使用这个函数组合这些表达式”,然后让编译器填入空白的其他情况并不难。
在简单的情况下,表达式都具有相同的类型,将它们放在一个列表然后折叠它也很有效 - 例如,使用unwords
和unlines
以这种方式构建字符串。 do
的好处是它将表达式与通用结构和兼容(但不完全相同)类型相结合。
事实上,同样的总的原则是从的“成语支架”符号的真正Applicative
纸:在哪里do
块使用新行的Elid到一元结构,成语支架利用并列提起的Elid功能应用。 Arrow
的proc
符号也类似,其他概念也可以用这种方式干净地表达,例如:
虽然将这些中的许多变成单个类型或完整的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环境实现了这些。
我不知道如何推广这些特殊的语法,但也许我没有给它足够的思考。
还有适合有单子的推广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.