29

我在某处读到 Rich Hickey 说:

“我认为延续在理论上可能很整洁,但在实践中却不是”

我不熟悉clojure。
1.clojure有延续吗?
2.如果没有,你不需要继续吗?我已经看到了很多很好的例子,尤其是这个家伙。什么是替代方案?
3. 如果有,是否有文件?

4

7 回答 7

27

在谈论延续时,您必须区分两种不同的延续:

  • 一流的延续——深度集成在语言(Scheme 或 Ruby)中的延续支持。Clojure 不支持一流的延续。

  • 延续传递风格(CPS)——CPS 只是一种编码风格,任何支持匿名函数的语言都将允许这种风格(这也适用于 Clojure)。

例子:

-- Standard function
double :: Int -> Int
double x = 2 * x

-- CPS-function – We pass the continuation explicitly
doubleCPS :: Int -> (Int -> res) -> res
doubleCPS x cont = cont (2 * x)
; Call
print (double 2)

; Call CPS: Continue execution with specified anonymous function
double 2 (\res -> print res)

继续阅读维基百科。

我不认为延续对于一门好的语言是必要的,但尤其是像 Haskell 这样的函数式语言中的一流延续和 CPS 可能非常有用(智能回溯示例)。

于 2009-07-23T17:14:39.707 回答
23

我编写了一个 cl-cont 的 Clojure 端口,它为 Common Lisp 添加了延续。

https://github.com/swannodette/delimc

于 2009-07-24T06:00:08.247 回答
18

抽象延续

延续是用于描述控制流语义的抽象概念。从这个意义上说,它们在任何提供控制运算符的语言中都存在和不存在(记住,它们是抽象的)(任何图灵完备的语言都必​​须如此),就像数字都存在(作为抽象实体)和不存在(作为有形实体)。

延续描述了控制效果,例如函数调用/返回、异常处理,甚至 goto。一个有充分基础的语言将被设计成具有建立在延续(例如,异常)之上的抽象。(也就是说,一个有充分根据的语言将包含在设计时考虑到延续的控制运算符。当然,一种语言将延续作为唯一的控制抽象公开是完全合理的,允许用户构建自己的顶部的抽象。)

头等舱延续

如果延续的概念被具体化为语言中的一等对象,那么我们就有了一个可以构建各种控制效果的工具。例如,如果一种语言具有一流的延续,但没有异常,我们可以在延续之上构造异常。

一流延续的问题

虽然在许多情况下,一流的延续是一个强大而有用的工具,但在语言中公开它们也有一些缺点:

  • 建立在延续之上的不同抽象在组合时可能会导致意外/不直观的行为。例如,finally如果我使用延续来中止计算,则可能会跳过一个块。
  • 如果可以随时请求当前延续,则必须对语言运行时进行结构化,以便可以随时生成当前延续的某种数据结构表示。这给运行时带来了一定程度的负担,无论好坏,通常被认为是“异国情调”。如果语言是托管的(例如 Clojure 托管在 JVM 上),那么该表示必须能够适应托管平台提供的框架。也可能存在语言想要维护的其他特性(例如,C 互操作),这些特性限制了解决方案的空间。诸如此类的问题增加了“阻抗失配”的可能性,并可能使高性能解决方案的开发变得非常复杂。

为语言添加一流的延续

通过元编程,可以为一门语言添加对一流延续的支持。通常,这种方法涉及将代码转换为延续传递样式 (CPS),其中当前延续作为显式参数传递给每个函数。

例如,David Nolen 的delimc库通过一系列宏转换实现了 Clojure 程序部分的定界延续。同样,我编写了pulley.cps,这是一个将代码转换为 CPS 的宏编译器,以及一个运行时库,以支持更多核心 Clojure 功能(例如异常处理)以及与本机 Clojure 代码的互操作.

这种方法的一个问题是如何处理本机 (Clojure) 代码和转换 (CPS) 代码之间的边界。具体来说,由于您无法捕获本机代码的延续,因此您需要禁止(或以某种方式限制)与基础语言的互操作,或者让用户承担确保上下文将允许他们希望捕获的任何延续实际被俘虏。

pulley.cps 倾向于后者,尽管已经进行了一些尝试以允许用户管理它。例如,可以禁止 CPS 代码调用本机代码。此外,还提供了一种机制来提供现有本机功能的 CPS 版本。

在具有足够强大类型系统的语言(例如 Haskell)中,可以使用类型系统来封装可能使用来自功能纯代码的控制操作(即延续)的计算。

概括

我们现在拥有直接回答您的三个问题所需的信息:

  1. 出于实际考虑,Clojure 不支持一流的延续。
  2. 从理论上讲,所有语言都建立在延续之上,但很少有语言将延续作为一等对象。但是,可以通过例如转换为 CPS 向任何语言添加延续。
  3. 查看delimc和/或pulley.cps的文档。
于 2016-05-19T23:00:56.973 回答
13

延续是语言的必要特征吗?

不,很多语言没有延续。

如果没有,你不需要继续吗?我已经看到了很多很好的例子,尤其是这个人的例子。什么是替代方案?

调用堆栈

于 2009-07-23T17:06:25.373 回答
7

延续的一个常见用途是实现控制结构:从函数返回、从循环中断、异常处理等。大多数语言(如 Java、C++ 等)将这些特性作为核心语言的一部分提供。有些语言没有(例如:Scheme)。相反,这些语言将延续作为第一类对象公开,并让程序员定义新的控制结构。因此,Scheme 应该被视为一个编程语言工具包,而不是一个完整的语言本身。

在 Clojure 中,我们几乎不需要直接使用延续,因为几乎所有的控制结构都是由语言/VM 组合提供的。尽管如此,一流的延续在有能力的程序员手中仍然是一个强大的工具。尤其是在 Scheme 中,延续优于其他语言中的等价对应物(如 C 中的 setjmp/longjmp 对)。本文对此有更多详细信息。

顺便说一句,了解 Rich Hickey 如何证明他对延续的看法会很有趣。任何链接?

于 2009-08-05T08:46:01.757 回答
6

Clojure(或者更确切地说clojure.contrib.monads)有一个延续单子;这是一篇描述其用法和动机的文章

于 2009-12-04T04:24:50.260 回答
-1

嗯...... Clojure->实现了你所追求的......但是用宏代替

于 2014-01-07T18:54:14.937 回答