我目前正在阅读" 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)
我无法得到的是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'
那为什么它在代码中有用呢?
答案 0 :(得分:10)
每个lambda表达式extends as far to the right as possible。
关于lambda抽象程度的语法是模棱两可的, 让表达式和条件。模糊性由解决 元规则,这些结构中的每一个都向右延伸 可能的。
使用width
和height
的表达式确实具有范围,因为它们位于引入它们的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身体,并且不会停留在+
,就像它不会停留在>>?
一样。