我们都喜欢do,而且我很好奇,如果这种替代语法在理论上可能在monad世界之外有用.如果是这样,它会简化哪些其他类型的计算?例如,为Applicative提供相同的东西是否有意义?
Tra*_*own 14
我的感觉是,很多Haskell新手不爱do可言,而赞成使用共同的论据之一Applicative,当你不需要的全部力量Monad在于组合子<$>,<*>等允许一个非常清晰和简洁的代码风格.
即使对于monadic代码,许多人更喜欢=<<明确使用而不是使用do符号.camccann 对你之前的问题<*>的回答为这种偏好提供了一个很好的论据.
我倾向于使用我的第一个草稿do,然后在修改时用组合器替换.这只是我自己(经验)和品味的问题:我通常最容易以更迫切的方式绘制事物(这更方便do),但我认为非do代码通常更漂亮.
另一方面,对于箭头,我无法想象不使用proc和命令do.元组刚刚变得如此丑陋.
关于do符号本身,它可能有助于考虑它实际上有什么用处.正如特拉维斯·布朗指出的那样,我之前曾主张使用带有Monads和相关类型的"函数应用程序"样式,但也有另一面:有些表达式根本无法直接编写为直接函数应用程序样式.例如,以下内容可以迅速使应用风格笨拙:
将这样的函数编写为单个表达式通常需要多个嵌套的lambdas,或者是一种荒谬的混淆废话,它使无点样式成为坏名称.阿do块,在另一方面,提供了一种用于与嵌入式控制流的中间结果容易嵌套作用域语法糖.
通常你可能会提取这样的子表达式并把它们放在一个where子句或者其他东西中,但是由于普通的值形成了一个带有函数应用程序(>>=)的Identitymonad - 就像monad一样 - 你可以想象在一个do块中编写这样一个函数,尽管人们可能会看着你好笑.
除了作用域/绑定之外,do块为你做的另一件事就是将子表达式链接在一起的运算符.想象一下"在这个块中使用这个函数组合这些表达式",然后让编译器填入空白的其他情况并不难.
在简单的情况下,如果表达式都具有相同的类型,把它们放在一个列表,然后折叠它工作得很好-建筑的字符串使用这种方式unwords,并unlines为实例.它的好处do是它将表达式与通用结构和兼容(但不完全相同)类型相结合.
事实上,同样的一般原则也适用于论文中的"成语括号"符号Applicative:凡do块使用换行符来消除monadic构造,成语括号使用并置来消除提升函数的应用.该proc音乐符号Arrow也是类似的,和其他概念可以在这种方式来表达干净为好,如:
虽然将这些中的许多变成单个类型或完整Monad实例并不太难,但对于一般概念来说,拥有一个统一的,可扩展的语法糖可能会很好.肯定有一个共同的线程将所有这些和更多的东西捆绑在一起,但这是一个与语法无关的更大的话题......
该do符号基本上是说:"根据需要转化为lambda表达式和分发的方式>>=字里行间".
当显而易见的是什么运算符用于推动所有事情时,省略并利用"换行符"运算符是很好的.
可编程换行将是处理材料列表,应用链等的好方法.要制作列表,您还需要一个"可编程的外部".实际上,您可以只取三个有意义的位并使它们全部可重载:
do.do.do.然后你可能不应该再打电话do了.也许它应该只是一个支架.
成语括号构成了考虑Applicatives的一种不错的方式,但它们并不是唯一可能的语法扩展.
菲利普·考德罗伊(Philippa Cowderoy)在一段时间后向haskell-cafe 发布了一个"Applicative do"符号的提议,观察到任何类似的函数:
foo = do
x <- bar
y <- baz
quux y 1234 x
Run Code Online (Sandbox Code Playgroud)
其中<-仅在最后一行中出现的变量可以使用Applicative实现 - 我实际上在方案中为此实现了一个基于语法规则的宏,我称之为"ado".
这对于应用效果的顺序与"自然顺序"不同并且假设Haskell中存在'ado'只会出于以下情况很有用:
foo = (\x y -> quux y 1234 x) <*> bar <*> baz
Run Code Online (Sandbox Code Playgroud)
但是,词汇范围规则有点令人不安.