部分应用程序在运行时如何表示?
当我在 Haskell 中编写类似 map (1+) list
的内容时,(1+)
的内部表示是什么?由于它是 (+)
的部分应用,因此参数 1
必须保存在某个地方,但我无法理解这一点。有人能给我一个简短的解释,柯里化和部分应用是如何实现的吗?
When I write something like map (1+) list
in Haskell, what is the internal representation of (1+)
? Since it is a partial application of (+)
, the argument 1
has to be saved somewhere, but I can't get my head around this. Can somebody give me a brief explanation, how currying and partial application is implemented?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
部分应用的函数(实际上,Haskell 堆中的几乎所有其他内容)都表示为闭包——一种结合了代码指针和参数槽的结构。具体来说,我们将未完全评估形式的值称为thunk。
请参阅之前关于盒装数据 以及关于如何表示 thunk 的 GHC 手册。
Partially applied functions (and, indeed, pretty much everything else in the Haskell heap) are represented as closures -- a structure combining a code pointer, and argument slots. Specifically, we call values that are not in a fully evaluated form thunks.
See this earlier question on boxed data and the GHC manual on how thunks are represented.
可以这样想:一切都由必须直接调用才能获得结果的一段代码(“thunk”)表示。当您编写文字
1
时,它会被编译为一段代码,在调用时返回 1(实际上是fromIntegral 1
),然后将该代码块用于文字 1 的位置。这也是惰性的关键:不是立即计算某些内容,而是创建一个 thunk,在调用时将执行计算。如果将该表达式传递给另一个函数,则传递的是包装器 thunk,因此计算不会发生,直到/除非需要显式检查其结果。在 Haskell 中,函数应用程序以相同的方式表示:一个 thunk 处理一个参数并返回一个 thunk,该 thunk 处理下一个参数或生成结果。所以
(1+)
是函数应用(+) 1
:(+)
是一个 thunk,期望传递一个数字,并且返回一个 thunk,希望传递另一个数字。由于(+)
是严格的,因此第二个 thunk 实际上执行加法,而不是返回必须调用才能执行实际加法的 thunk。因此,(1+)
计算为第二个 thunk,需要使用另一个数字来调用,该数字将在迭代list
map 提供>。Think of it this way: everything is represented by a chunk of code (a "thunk") that has to be invoked directly to get a result. When you write a literal
1
, it gets compiled to a chunk of code that returns 1 (actually,fromIntegral 1
) when invoked, and that chunk of code is then used in place of the literal 1. This is also key to laziness: instead of calculating something immediately, a thunk is created that when invoked will do the calculation. If you pass that expression to another function, it's the wrapper thunk that's passed, and so the calculation doesn't happen until/unless something needs to explicitly examine its result.In Haskell, function applications are represented the same way: a thunk that processes one parameter and returns a thunk that either processes the next parameter or produces the result. So
(1+)
is the function application(+) 1
:(+)
is a thunk that expects to be passed a single number and returns a thunk that expects to be passed another single number. Since(+)
is strict, that second thunk actually does the addition instead of returning a thunk that has to be invoked to do the actual addition. So(1+)
evaluates to that second thunk, which needs to be invoked with another number which will be supplied bymap
as it iterates overlist
.您可能还想查看实现函数式语言:教程,西蒙·佩顿·琼斯和大卫·莱斯特所著的书。
You may also want to check out Implementing Functional Languages: A Tutorial, a book by Simon Peyton Jones and David Lester.