我正在尝试了解范围在do块中的工作原理。
如果我有以下代码:
l = [1, 2, 3]
m = [1, 2]
然后这很好用
res = do
a <- l
b <- m
return (a, b)
返回m
和l
的笛卡尔积。
要理解范围,我尝试以不同的形式重写它(没有做块)
我知道块块只是一元操作的语法糖,所以我尝试“取出”它并使用this并提出这个:
res = l >>= (\a -> m) >>= (\b -> return (a, b))
奇怪的是我收到此错误Not in scope: ‘a’
。
任何人都可以告诉我我做错了什么,可能还有,范围是如何工作的,因为看起来真的看起来像do块中的return
能够访问?
非常感谢
答案 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
。