DAR*_*UCK 4 monads haskell scoping
我试图理解范围在do块中是如何工作的.
如果我有以下代码:
l = [1, 2, 3]
m = [1, 2]
Run Code Online (Sandbox Code Playgroud)
然后这工作正常
res = do
a <- l
b <- m
return (a, b)
Run Code Online (Sandbox Code Playgroud)
并返回笛卡尔乘积m和l.
为了理解范围,我试图以不同的形式重写它(没有做块)
我知道块只是monadic操作的语法糖,所以我试图"unsugar"它并使用它并想出了这个:
res = l >>= (\a -> m) >>= (\b -> return (a, b))
Run Code Online (Sandbox Code Playgroud)
奇怪的是我收到了这个错误Not in scope: ‘a’.
任何人都可以告诉我我做错了什么,可能,范围如何工作,因为它真的看起来像魔术return块在do块中能够访问?
非常感谢你
Dan*_*zer 12
问题是代码中lambda的范围不太对.它应该一直延伸到表达式的末尾,而不仅仅是小计算.你的代码应该是desugar
l >>= (\a -> m >>= (\b -> return (a, b))
Run Code Online (Sandbox Code Playgroud)
你可以顺便放下括号,这样可以让它更愉快.
l >>= \a -> m >>= \b -> return (a, b)
Run Code Online (Sandbox Code Playgroud)
但这种模糊了意义.如果你想要明确,我们可以转换为前缀表示法并说
bind a f = a >>= f
bind l (\a -> bind m (\b -> return (a, b))
Run Code Online (Sandbox Code Playgroud)
也许剥离一些操作员的糖有帮助.
注意>> ='嵌套在 lambda 内部,而不是它周围.这可确保a保留在范围内.事实上,这种嵌套是手工写出来的一点点痛苦,这是写法的推动力的一部分:)
问题出在你的括号上.你写
res = l >>= (\a -> m) >>= (\b -> return (a, b))
Run Code Online (Sandbox Code Playgroud)
但你需要的是
res = l >>= (\a -> m >>= (\b -> return (a, b)))
Run Code Online (Sandbox Code Playgroud)
也可以写
res = l >>= \a -> m >>= \b -> return (a, b)
Run Code Online (Sandbox Code Playgroud)
你a过早地结束了lambda表达式绑定,然后尝试使用a.