匿名函数的范围可见性

zer*_*kms 3 lambda haskell scope anonymous-function

我目前正在阅读"真实世界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)
Run Code Online (Sandbox Code Playgroud)

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

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'
Run Code Online (Sandbox Code Playgroud)

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

Cir*_*dec 10

每个lambda表达式尽可能向右延伸.

关于lambda抽象,let表达式和条件的范围,语法是模糊的.模糊性由元规则解决,即每个构造都尽可能向右延伸.

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


ick*_*fay 8

你可能会这样读:

(\(width, s) -> getNat s) >>? (\(height, s) -> getNat s) >>? ...
Run Code Online (Sandbox Code Playgroud)

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

(\(width, s) -> ((getNat s) >>? (\(height, s) -> (getNat s) >>? (...))))
Run Code Online (Sandbox Code Playgroud)

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

要了解原因,请考虑将\x -> x + 5其解释为\x -> (x + 5)而不是(\x -> x) + 5.该\是在消费它的拉姆达身体非常贪婪,并在不会停止+,只是因为它不会在停止>>?.