21

我发现优先级和关联性是我理解语法乍一看试图表达的 Haskell 代码的一大障碍。

例如,

blockyPlain :: Monad m => m t -> m t1 -> m (t, t1)
blockyPlain xs ys = xs >>= \x -> ys >>= \y -> return (x, y)

通过实验,我终于明白了意思,

blockyPlain xs ys = xs >>= (\x -> (ys >>= (\y -> return (x, y))))

代替

blockyPlain xs ys = xs >>= (\x -> ys) >>= (\y -> return (x, y))

其工作方式为:

*Main> blockyPlain [1,2,3] [4,5,6]
[(1,4),(1,5),(1,6),(2,4),(2,5),(2,6),(3,4),(3,5),(3,6)]

我可以从 ghci 中获取 (>>=) 作为运算符 (infixl 1 >>=) 的信息。

但是没有关于 -> 的信息,因为它不是运算符。

你们中的某个人可以提供一些参考以使这个语法更容易掌握吗?

4

2 回答 2

26

lambda 的规则非常简单:lambda 的主体尽可能向右延伸,而不会碰到不平衡的括号。

f (\x -> foo (bar baz) *** quux >>= quuxbar)
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                       body
于 2012-06-28T02:54:45.390 回答
7

一个好的经验法则似乎是,您永远不能创建优先于内置句法结构的自定义运算符。例如考虑这个例子:

if b then f *** x else f *** y

不管 的关联性如何***,没有人会期望它绑定为:

(if b then f *** x else f) *** y

Haskell 中没有很多语法结构(do并且case由于布局语法而有些特殊),但let可以用作另一个示例:

(let x = y in y *** x) /= ((let x = y in y) *** x) 
于 2012-06-28T12:17:18.507 回答