web-dev-qa-db-ja.com

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

提案(P -> Q) -> QおよびP \/ 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 = idおよびto . from = id

18
user12333506

命題_(P -> Q) -> Q_と_P \/ Q_は同等です。

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

建設的な論理では 除外された中間の法則 がありません。つまり、「Pが真であるか、Pが真でないかのどちらかで」始めることはできません。

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

  • pがtrueの場合(つまり、(_x :: P_)がある場合)、_Left x_を返します。
  • pがfalseの場合、Haskellでは_nx :: P -> Void_関数を使用できます。次に、_absurd . nx :: P -> Q_(すべての型をピークにすることができます。Q)を取得し、_absurd . nx_で指定されたf :: (P -> Q) -> Q)を呼び出して、型Qの値を取得します。

タイプの一般的な機能がないという問題:

_lem :: forall p. Either p (p -> Void)
_

いくつかの具体的なタイプがあります。 Boolには人が住んでいるので、

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

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

14
phadej

いいえ、不可能です。 Q = Void

Either P QEither P VoidPに同型です。

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の対応によると、これは直観主義ロジックのトートロジーになります。

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

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

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

9
chi

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

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

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

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

4
Carl

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

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は、たまたま選択したTuringマシン構成が停止するという命題をエンコードできるためです。


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)
2
dfeuer

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

Either a bを構築するには、aまたはbの値が必要です。 a値を作成する方法はありませんが、呼び出すことができるbを返す関数はあります。そのためには、abに変換する関数を提供する必要がありますが、型が不明な場合、定数bを返す関数を作成できます。そのb値を取得するために、以前とは異なる方法でそれを構築することはできないため、これは循環推論になり、fixpointを作成するだけで解決できます。

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