Gibt es eine Möglichkeit, eine Funktion vom Typ ((a -> b) -> b) -> entweder ab zu realisieren?

18

Vorschläge (P -> Q) -> QundP \/ Q sind gleichwertig.

Gibt es eine Möglichkeit, diese Gleichwertigkeit in Haskell zu bezeugen:

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 = ???

so dass

from . to = idund to . from = id?


quelle
Mir scheint klar, dass dies unmöglich ist, aber vielleicht irre ich mich. Wenn ja, ist ein nützlicher Ausgangspunkt, dass eine Funktion mit dem vollständig polymorphen Typ ((a -> b) -> b)isomorph ist zu a: Die einzig mögliche Implementierung ist g f = f someHardcodedA.
Amalloy
1
@amalloy gibt es eine andere mögliche Implementierung:g = const someHardcodedB
Fyodor Soikin
Ah natürlich. Es ist entweder aoder b. Macht Sinn.
Amalloy
1
Wenn Haskell call / cc hätte, to f = callcc (\k -> k (Right (f (\a -> k (Left a)))))würde das funktionieren. (Dies ist ein gültiger klassischer Beweis für die Implikation.)
Benrg

Antworten:

14

Vorschläge (P -> Q) -> QundP \/ Q sind gleichwertig.

Dies gilt in der klassischen Logik, nicht jedoch in der konstruktiven Logik.

In der konstruktiven Logik haben wir kein Gesetz der ausgeschlossenen Mitte , dh wir können unser Denken nicht mit "entweder P ist wahr oder P ist nicht wahr" beginnen.

Klassisch argumentieren wir wie:

  • Wenn P wahr ist (dh wir haben ( x :: P)), dann kehre zurück Left x.
  • Wenn P falsch ist, dann hätten wir in Haskell eine nx :: P -> VoidFunktion. Dann absurd . nx :: P -> Q(wir jede Art Spitze können, nehmen wir Q) und rufen gegeben f :: (P -> Q) -> Q)mit absurd . nxWert des Typs zu erhalten Q.

Das Problem, dass es keine allgemeine Funktion eines Typs gibt:

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

Für einige konkrete Typen gibt es zB Boolbewohnt, damit wir schreiben können

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

aber im Allgemeinen können wir nicht.

Phadej
quelle
9

Nein, das ist unmöglich. Betrachten Sie den Sonderfall wo Q = Void.

Either P Qist dann Either P Void, was isomorph zu ist 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

Wenn wir also einen Funktionsbegriff hätten

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

Wir könnten auch einen Begriff haben

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

Laut der Curry-Howard-Korrespondenz wäre dies eine Tautologie in der intuitionistischen Logik:

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

Aber das Obige ist die Eliminierung der doppelten Negation, die in der intuitionistischen Logik bekanntermaßen nicht zu beweisen ist - daher ein Widerspruch. (Die Tatsache, dass wir es in klassischer Sprache beweisen konnten Logik ist nicht relevant.)

(Schlussbemerkung: Dies setzt voraus, dass unser Haskell-Programm beendet wird. Natürlich undefinedkönnen wir mit unendlicher Rekursion und ähnlichen Methoden, um tatsächlich zu vermeiden, dass ein Ergebnis zurückgegeben wird, jeden Typ in Haskell bewohnen.)

Chi
quelle
4

Nein, das ist nicht möglich, aber etwas subtil. Das Problem ist, dass die Typvariablen aund buniversell quantifiziert werden.

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

aund bsind universell quantifiziert. Der Anrufer wählt den Typ aus, sodass Sie nicht einfach einen Wert für einen der beiden Typen erstellen können. Dies bedeutet, dass Sie nicht einfach einen Wert vom Typ erstellen können, Either a bwährend Sie das Argument ignorieren f. Die Verwendung fist aber auch unmöglich. Ohne zu wissen, welche Typen aund welche Typen vorhanden bsind, können Sie keinen Wert für den Typ erstellen, a -> ban den übergeben werden soll f. Es sind einfach nicht genügend Informationen verfügbar, wenn die Typen universell quantifiziert werden.

Was den Grund betrifft, warum der Isomorphismus in Haskell nicht funktioniert - sind Sie sicher, dass diese Sätze in einer konstruktiven intuitionistischen Logik gleichwertig sind? Haskell implementiert keine klassische deduktive Logik.

Carl
quelle
2

Wie andere betont haben, ist dies unmöglich, weil wir nicht das Gesetz der ausgeschlossenen Mitte haben. Lassen Sie mich das etwas expliziter durchgehen. Angenommen, wir haben

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

und wir setzen b ~ Void. Dann bekommen wir

-- 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

Lassen Sie uns nun die doppelte Negation des Gesetzes der ausgeschlossenen Mitte beweisen, wie es auf einen bestimmten Satz angewendet wird .

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

Also jetzt

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

lemkann eindeutig nicht existieren, weil ader Vorschlag kodiert werden kann, dass jede Turing-Maschinenkonfiguration, die ich zufällig auswähle, anhält.


Lassen Sie uns überprüfen, ob dies lemausreicht:

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)
dfeuer
quelle
0

Ich habe keine Ahnung, ob dies logisch gültig ist oder was es für Ihre Äquivalenz bedeutet, aber ja, es ist möglich, eine solche Funktion in Haskell zu schreiben.

Um einen zu konstruieren Either a b, benötigen wir entweder einen aoder einen bWert. Wir haben keine Möglichkeit, einen aWert zu konstruieren , aber wir haben eine Funktion, die eine zurückgibt b, die wir aufrufen könnten. Dazu müssen wir eine Funktion angeben , die ein ain ein konvertiert. bDa die Typen jedoch unbekannt sind, können wir bestenfalls eine Funktion erstellen, die eine Konstante zurückgibt b. Um diesen bWert zu erhalten, können wir ihn nicht anders als zuvor konstruieren, daher wird dies zu einer Zirkelschlussfolgerung - und wir können dies lösen, indem wir einfach einen Fixpunkt erstellen :

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