有没有办法实现((a -> b) -> b) -> Either a b 类型的函数?

Posted

技术标签:

【中文标题】有没有办法实现((a -> b) -> b) -> Either a b 类型的函数?【英文标题】:Is there a way to realize a function of type ((a -> b) -> b) -> Either a b? 【发布时间】:2020-03-03 06:10:25 【问题描述】:

命题(P -> Q) -> QP \/ Q 是等价的。

有没有办法在 Haskell 中见证这种等价性:

from :: Either a b -> ((a -> b) -> b)
from x = case x of
         Left a -> \f -> f a
         Right b -> \f -> b

to :: ((a -> b) -> b) -> Either a b
to = ???

这样

from . to = idto . from = id?

【问题讨论】:

在我看来这是不可能的,但也许我错了。如果是这样,一个有用的起点是具有完全多态类型((a -> b) -> b) 的函数与a 同构:唯一可能的实现是g f = f someHardcodedA @amalloy 还有另一种可能的实现方式:g = const someHardcodedB 啊,当然。它是ab。有道理。 如果 Haskell 有 call/cc,那么 to f = callcc (\k -> k (Right (f (\a -> k (Left a))))) 就可以了。 (这是隐含的有效经典证明。) 【参考方案1】:

命题(P -> Q) -> QP \/ Q 是等价的。

这在经典逻辑中是正确的,但在构造逻辑中却不是。

在建设性逻辑中,我们没有law of excluded middle,即我们不能从“P 为真或 P 不为真”开始思考。

通常我们的推理如下:

如果 P 为真(即我们有 (x :: P))然后返回 Left x。 如果 P 为假,那么在 Haskell 中我们将拥有 nx :: P -> Void 函数。然后absurd . nx :: P -> Q(我们可以峰值任何类型,我们采用Q)并调用给定的f :: (P -> Q) -> Q)absurd . nx 以获取Q 类型的值。

问题,没有一个类型的通用函数:

lem :: forall p. Either p (p -> Void)

对于一些具体的类型,例如Bool 有人居住所以我们可以写

lemBool :: Either Bool (Bool -> Void)
lemBool = Left True -- arbitrary choice

但总的来说,我们不能。

【讨论】:

【参考方案2】:

不,这是不可能的。考虑Q = Void 的特殊情况。

Either P Q 则为Either P Void,与P 同构。

iso :: P -> Either P Void
iso = Left

iso_inv :: Either P Void -> P
iso_inv (Left p)  = p
iso_inv (Right q) = absurd q

因此,如果我们有一个函数项

impossible :: ((P -> Void) -> Void) -> Either P Void

我们也可以有一个术语

impossible2 :: ((P -> Void) -> Void) -> P
impossible2 = iso_inv . impossible

根据 Curry-Howard 的对应关系,这将是 intuitionistic 逻辑中的重言式:

((P -> False) -> False) -> P

但以上是双重否定消除,众所周知,在直觉主义逻辑中是不可能证明的——因此是矛盾的。 (我们可以在 classical 逻辑中证明它的事实并不相关。)

(最后说明:这里假设 Haskell 程序终止。当然,使用无限递归、undefined 和类似的方法来实际避免返回结果,我们可以在 Haskell 中使用任何类型。)

【讨论】:

【参考方案3】:

不,这是不可能的,但它有点微妙。问题是类型变量ab 是通用量化的。

to :: ((a -> b) -> b) -> Either a b
to f = ...

ab 被普遍量化。调用者选择它们的类型,因此您不能只创建任一类型的值。这意味着您不能只创建Either a b 类型的值而忽略参数f。但是使用f 也是不可能的。在不知道ab 是什么类型的情况下,您无法创建a -> b 类型的值来传递给f。当类型被普遍量化时,没有足够的信息可用。

至于为什么同构在 Haskell 中不起作用 - 你确定这些命题在建设性直觉主义逻辑中是等价的吗? Haskell 没有实现经典的演绎逻辑。

【讨论】:

【参考方案4】:

正如其他人指出的那样,这是不可能的,因为我们没有排中律。让我更明确地讨论一下。假设我们有

bogus :: ((a -> b) -> b) -> Either a b

我们设置b ~ Void。然后我们得到

-- chi calls this `impossible2`.
double_neg_elim :: ((a -> Void) -> Void) -> a
bouble_neg_elim f = case bogus f of
             Left a -> a
             Right v -> absurd v

现在,让我们证明排中律的双重否定应用于特定命题

nnlem :: forall a. (Either a (a -> Void) -> Void) -> Void
nnlem f = not_not_a not_a
  where
    not_a :: a -> Void
    not_a = f . Left

    not_not_a :: (a -> Void) -> Void
    not_not_a = f . Right

现在

lem :: Either a (a -> Void)
lem = double_neg_elim nnlem

lem 显然不存在,因为a 可以编码我碰巧选择的任何图灵机配置都会停止的命题。


让我们验证lem 是否足够:

bogus :: forall a b. ((a -> b) -> b) -> Either a b
bogus f = case lem @a of
  Left a -> Left a
  Right na -> Right $ f (absurd . na)

【讨论】:

【参考方案5】:

我不知道这在逻辑上是否有效,或者它对您的等效性意味着什么,但是可以在 Haskell 中编写这样的函数。

要构造Either a b,我们需要ab 值。我们没有任何方法可以构造一个a 值,但是我们确实有一个函数可以返回一个我们可以调用的b。为此,我们需要提供一个将a 转换为b 的函数,但鉴于类型未知,我们最多可以创建一个返回常量b 的函数。要获得 b 的值,我们不能以任何其他方式构造它,所以这变成了循环推理 - 我们可以通过简单地创建一个 fixpoint 来解决这个问题:

to :: ((a -> b) -> b) -> Either a b
to f = let x = f (\_ -> x) in Right x

【讨论】:

以上是关于有没有办法实现((a -> b) -> b) -> Either a b 类型的函数?的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法在它的孩子中修改嵌套类的实现?

android A apk控制B apk中英文切换有啥办法实现

有没有办法在音频 B 也开始播放后修复音频 A 的播放?

redis实现消息队列

对于每个 ID 组,考虑到已排序的 A 字段,有没有办法检查 B 字段中值的重复? (见下面的例子)

有没有办法用 AVX2 编写 _mm256_shldi_epi8(a,b,1) ? (向量之间每 8 位元素移位一位)