了解使用haskell monads的范围

时间:2016-04-05 16:01:47

标签: haskell monads scoping

我正在尝试了解范围在do块中的工作原理。

如果我有以下代码:

l = [1, 2, 3]
m = [1, 2]

然后这很好用

res = do
    a <- l
    b <- m
    return (a, b)

返回ml的笛卡尔积。

要理解范围,我尝试以不同的形式重写它(没有做块)

我知道块块只是一元操作的语法糖,所以我尝试“取出”它并使用this并提出这个:

res = l >>= (\a -> m) >>= (\b -> return (a, b))

奇怪的是我收到此错误Not in scope: ‘a’

任何人都可以告诉我我做错了什么,可能还有,范围是如何工作的,因为看起来真的看起来像do块中的return能够访问?

非常感谢

2 个答案:

答案 0 :(得分:12)

问题是代码中lambda的范围不太正确。它应该一直延伸到表达式的末尾,而不仅仅是小计算。你的代码应该去了

 l >>= (\a -> m >>= (\b -> return (a, b))

顺便说一句,你可以放下括号,这样可以让它更愉快。

 l >>= \a -> m >>= \b -> return (a, b)

但这种模糊了含义。如果你想要明确地表达,我们可以转换为前缀表示法并说出

 bind a f = a >>= f
 bind l (\a -> bind m (\b -> return (a, b))

或许可以剥夺一些操作员糖的帮助。

请注意&gt;&gt; ='窝里面 lambda,而不是它周围。这可确保a保持在范围内。事实上,这种嵌套手工写出来有点痛苦,这是写法的推动力的一部分:)

答案 1 :(得分:7)

问题在于你的括号。你写了

res = l >>= (\a -> m) >>= (\b -> return (a, b))

但你需要的是

res = l >>= (\a -> m >>= (\b -> return (a, b)))

也可以写

res = l >>= \a -> m >>= \b -> return (a, b)

您过早地结束了绑定a的lambda表达式,然后尝试使用a