タイプ((a-> b)-> b)->どちらかのabの関数を実現する方法はありますか?


18

命題(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。可能な実装はだけです。
アマロイ

1
@amalloy別の可能な実装があります:g = const someHardcodedB
フョードルSoikin

ああ、もちろん。それはどちらかですab。理にかなっています。
アマロイ

1
Haskellがcall / ccを使用している場合、to f = callcc (\k -> k (Right (f (\a -> k (Left a)))))機能します。(これはその意味の有効な古典的な証明です。)
benrg

回答:


14

命題(P -> Q) -> QP \/ Q同等です。

これは、古典的論理には当てはまりますが、構成的論理には当てはまりません。

建設的な論理では、ミドルを除外する法則はありません。つまり、「Pが真であるか、Pが真ではない」から考えることはできません。

古典的には次のように推論します。

  • Pがtrueの場合(つまり、(x :: P)がある場合)は戻りLeft xます。
  • Pがfalseの場合、Haskellで言えばnx :: P -> Void機能します。次にabsurd . nx :: P -> Q(任意の型のピークをとることができます)、typeの値を取得するために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

しかし、繰り返しになりますが、一般的にはできません。


9

いいえ、不可能です。特別な場合を考え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

カリー・ハワード通信によると、これは直観主義的なロジックのトートロジーになります:

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

しかし、上記は二重否定の排除であり、証明することが不可能であることがよく知られています 直観主義的な論理でため、矛盾です。(古典的な論理でそれを証明できるという事実は関係ありません。)

(最後の注意:これは、Haskellプログラムが終了することを前提としています。もちろん、無限再帰、undefinedなどの結果を実際に返さないようにするための同様の方法を使用すると、Haskellのどの型でも使用できます。)


4

いいえ、それは不可能ですが、少し微妙です。問題は、型変数でaありb、普遍的に数量化されていることです。

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

aそしてb普遍的に定量化されています。呼び出し元はそれらのタイプを選択するため、どちらのタイプの値も作成できません。これEither a bは、引数を無視してtypeの値を作成できないことを意味しますf。しかし、使用するfことも不可能です。型abは何かを知らないと、a -> bに渡す型の値を作成できませんf。タイプが普遍的に定量化されている場合、十分な情報が得られません。

なぜ同型がHaskellで機能しないのか-これらの命題は、建設的な直観主義のロジックで同等であると確信していますか?Haskellは古典的な演繹論理を実装していません。


2

他の人が指摘したように、私たちは排除された中間者の法則を持っていないので、これは不可能です。もう少しはっきりと説明します。私たちが持っていると仮定します

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

lema私がたまたま選択したチューリングマシンの構成が停止するという命題をエンコードできるため、明らかに存在できません。


それで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)

0

これが論理的に有効であるかどうか、またはそれがあなたの等価性にとって何を意味するのかはわかりませんが、そのような関数をHaskellで作成することは可能です。

を作成するEither a bには、aまたはのいずれかが必要ですb値です。a値を構築する方法はありませんが、b呼び出すことができるを返す関数はあります。そのためには、機能を提供する必要が改宗ことab、しかし種類を与えられたが、我々は最高の状態で定数を返す関数を作ることができ不明ですb。そのb値を取得するために、以前以外の方法でそれを構築することはできないため、これは循環推論になります。そして、固定点を作成するだけでそれを解決できます。

to :: ((a -> b) -> b) -> Either a b
to f = let x = f (\_ -> x) in Right x
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.