匿名函数的范围可见性

时间:2014-12-14 03:30:03

标签: haskell lambda scope anonymous-function

我目前正在阅读" Real World Haskell"并被那里实现的一个功能搞糊涂了:

parseP5_take2 :: L.ByteString -> Maybe (Greymap, L.ByteString)
parseP5_take2 s =
    matchHeader (L8.pack "P5") s       >>?
    \s -> skipSpace ((), s)           >>?
    (getNat . snd)                    >>?
    skipSpace                         >>?
    \(width, s) ->   getNat s         >>?
    skipSpace                         >>?
    \(height, s) ->  getNat s         >>?
    \(maxGrey, s) -> getBytes 1 s     >>?
    (getBytes (width * height) . snd) >>?
    \(bitmap, s) -> Just (Greymap width height maxGrey bitmap, s)

我无法得到的是widthheight和其他人如何从匿名函数范围泄露并在最新的表达式中可用。

RWH中的确切位置:http://book.realworldhaskell.org/read/code-case-study-parsing-a-binary-data-format.html#id624895

简化的自己的代码失败了,因为我期待:

Prelude> (\x -> x) 5 + (\y -> x) 6

<interactive>:4:22: Not in scope: `x'

那为什么它在代码中有用呢?

2 个答案:

答案 0 :(得分:10)

每个lambda表达式extends as far to the right as possible

  

关于lambda抽象程度的语法是模棱两可的,   让表达式和条件。模糊性由解决   元规则,这些结构中的每一个都向右延伸   可能的。

使用widthheight的表达式确实具有范围,因为它们位于引入它们的lambda中。

答案 1 :(得分:8)

你可能会这样读:

(\(width, s) -> getNat s) >>? (\(height, s) -> getNat s) >>? ...

在那种情况下,你是对的;你不能访问那些超出范围的东西。但它实际上是这样的:

(\(width, s) -> ((getNat s) >>? (\(height, s) -> (getNat s) >>? (...))))

用语言来说,这些表达并不是独立的;它实际上是嵌套的,虽然它们的缩进没有清楚地表明它,你当然可以从外部范围访问它。

要了解原因,请考虑将\x -> x + 5解释为\x -> (x + 5)而不是(\x -> x) + 5\非常贪婪地消耗它的lambda身体,并且不会停留在+,就像它不会停留在>>?一样。