Haskell:将lambda表达式与bind函数一起使用时的变量范围

时间:2010-08-20 17:29:35

标签: haskell lambda scope bind monads

以下行按预期工作,但我有点担心原因:

getLine >>= \x-> getLine >>= \y-> return [x, y]

考虑添加括号来定义lambda表达式:

getLine >>= (\x-> getLine) >>= (\y-> return [x, y])

第二行是错误的,因为xreturn中使用时不在范围内,我很满意。我担心的是,在第一行中,x的范围似乎已经“泄露”了。

这种'泄漏'被认为是不好的做法吗?我很困惑它是如何保持在范围内而不是在\x -> getLine表达后立即丢失。

4 个答案:

答案 0 :(得分:14)

如果根据haskell的优先规则正确地为第一行加上括号,则得到:

getLine >>= (\x-> getLine >>= (\y-> return [x, y]))

这很明显第二个lambda在第一个lambda中,因此访问第一个lambda的变量没有问题。

答案 1 :(得分:12)

你的括号根本就是错误的。正确的括号是

getLine >>= (\x -> getLine >>= (\y -> return [x, y]))

因此,x当然是在身体中定义的。

请注意,此功能特别有用,因为您可以格式化以下代码:

getLine >>= \x ->
getLine >>= \y ->
return [x, y]

几乎是

do
  x <- getLine
  y <- getLine
  return [x, y]

但没有任何特殊语法。

答案 2 :(得分:2)

Haskell语法遵循“最大munch”规则:每个语法元素尽可能地扩展,直到进一步扩展它会导致错误。由于它可以很好地将“\x ->”的范围一直扩展到最终,这就是它的作用。

答案 3 :(得分:1)

x表达式中对return的引用称为closure。这是函数式编程语言的典型特征。在像Haskell这样的纯函数式编程语言中,没有理由担心。这是一个非常好的功能。在“混合”函数式编程语言中,如F#(和C#这些天),闭包确实会导致意外行为。