为什么我们可以实现call / cc,但是经典逻辑(直觉+ call / cc)不是建设性的?

时间:2014-07-12 09:39:08

标签: functional-programming continuations callcc curry-howard

直觉逻辑,具有建设性,是函数式编程中类型系统的基础。经典逻辑不具有建设性,特别是被排除在中间的法律A∨¬A(或其等价物,如double negation eliminationPierce's law)。

但是,我们可以实现(构建)call-with-current-continuation运算符(AKA call / cc ),例如在Scheme中。那么 call / cc 为什么不建设性?

1 个答案:

答案 0 :(得分:10)

问题在于,使用 call / cc ,结果取决于评估顺序。考虑Haskell中的以下示例。假设我们有 call / cc 运算符

callcc :: ((a -> b) -> a) -> a
callcc = undefined

让我们来定义

example :: Int
example =
    callcc (\s ->
        callcc (\t ->
            s 3 + t 4
        )
    )

这两个函数都是纯函数,因此example的值应该唯一确定。但是,这取决于评估顺序。如果首先评估s 3,则结果为3;如果首先评估t 4,则结果为4

这对应于continuation monad中的两个不同的例子(强制执行顺序):

-- the result is 3
example1 :: (MonadCont m) => m Int
example1 =
    callCC (\s ->
        callCC (\t -> do
            x <- s 3
            y <- t 4
            return (x + y)
        )
    )

-- the result is 4
example2 :: (MonadCont m) => m Int
example2 =
    callCC (\s ->
        callCC (\t -> do
            y <- t 4 -- switched order
            x <- s 3
            return (x + y)
        )
    )

它甚至取决于是否对某个术语进行评估:

example' :: Int
example' = callcc (\s -> const 1 (s 2))

如果对s 2进行评估,则结果为2,否则为1

这意味着 Church-Rosser theorem call / cc 存在的情况下不会。特别是,条款不再具有唯一normal forms

也许有一种可能性是将 call / cc 视为非确定性(非建设性)运算符,它结合了(不)按各种顺序评估不同子项所获得的所有可能结果。然后,程序的结果将是所有这些可能的正常形式的集合。但是,标准的 call / cc 实现将始终只选择其中一个(取决于其特定的评估顺序)。