用咖喱语言的CPS
如果像lambda演算或Ocaml这样的curry语言中的CPS如何有意义?从技术上讲,所有函数都有一个参数。所以说我们在一种语言中添加了CPS版本:
cps-add k n m = k ((+) n m)
我们称之为
(cps-add random-continuation 1 2)
这与以下相同:
(((cps-add random-continuation) 1) 2)
我已经看到那里有两个不是尾调用的调用,实际上是一个复杂的嵌套表达式,(cps-add random-continuation)
返回一个值,即一个消耗数字的函数,然后返回一个消耗另一个数字的函数,然后传递两者的总和那个random-continuation
。但是我们无法通过简单地将其转换为CPS来解决这个值,因为我们只能给每个函数一个参数。我们需要至少有两个为继续和“实际”论证腾出空间。
还是我完全错过了什么?
没有找到相关结果
已邀请:
3 个回复
肉簧咸缮
monad中,它将值ѭ6trans转换为带有一个参数的高阶函数,适用于
。 所以,首先,这里是常规Haskell中的1 + 2:
这里是继续monad:
......不是非常有用的信息。为了看看发生了什么,让我们拆开monad。首先,删除
表示法:
函数将一个值提升到monad中,在这种情况下实现为
,或使用中缀运算符部分为
。
运算符(读“绑定”)将monad中的计算链接在一起,在这种情况下实现为
。将绑定函数更改为前缀形式并替换为lambda,并为清晰起见添加一些重命名:
减少一些功能应用:
还有一些最终的重新排列和重命名:
换句话说:函数的参数已从数字更改为带有数字的函数,并返回整个表达式的最终结果,正如您所期望的那样。 编辑:一位评论者指出,
本身仍然采用咖喱风格的两个参数。这是明智的,因为它不直接使用延续,但不是必需的。否则,你需要首先在参数之间分解函数:
然后像这样使用它:
请注意,这与早期版本没有什么不同;它只是将每个部分应用程序的结果打包为延续,而不仅仅是最终结果。由于函数是一等值,因此持有数字的CPS表达式与持有函数的CPS表达式之间没有显着差异。 请记住,我在这里以非常冗长的方式写出来,以明确表示某些事物处于延续传递风格的所有步骤。 附录:您可能会注意到最终表达式与monadic表达式的脱糖版本非常相似。这不是巧合,因为monadic表达式的向内嵌套性质使它们能够根据先前的值改变计算结构,这与继续传递风格密切相关;在这两种情况下,你在某种意义上都有一种因果关系的概念。
谦响局豢报
未经证实的原语,你问的是什么是翻译
(这个
忠实代表OCaml的
运营商)
在语法上等同于
因此,您应用CPS转换¹并获取
如果你想要一个看起来更像是你愿意写的东西的翻译代码,你可以设计一个更精细的转换,实际上将已知的arity函数视为非curried函数,并将所有参数作为一个整体进行处理(就像你在非咖喱语言,以及功能编译器已经出于明显的性能原因而已。 ¹:我写了“CPS变换”,因为没有“真正的CPS翻译”。已经设计了不同的翻译,产生或多或少与延续相关的垃圾。正式的CPS翻译通常直接在lambda演算上定义,所以我想你在考虑一个不太正式,更加手工制作的CPS变换。 CPS的良好属性(作为一种程序方面的风格,而不是对此风格的特定转换)是评估的顺序是完全明确的,并且所有调用都是尾调用。只要你尊重这些,你就可以做得相对自由。因此,专门处理curryfied功能是完全正确的。 备注:如果您假设编译器检测并优化cps-add实际上总是需要3个参数,并且不构建中间闭包,那么您的
版本也可以被认为是尾递归的。这可能看起来很牵强,但在使用这些语言推理非CPS程序中的尾部调用时,我们使用的假设完全相同。
冲汉