直觉逻辑,具有建设性,是函数式编程中类型系统的基础。经典逻辑不具有建设性,特别是被排除在中间的法律A∨¬A(或其等价物,如double negation elimination或Pierce's law)。
但是,我们可以实现(构建)call-with-current-continuation运算符(AKA call / cc ),例如在Scheme中。那么 call / cc 为什么不建设性?
答案 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 实现将始终只选择其中一个(取决于其特定的评估顺序)。