Les propositions (P -> Q) -> Q
et P \/ Q
sont équivalentes.
Existe-t-il un moyen de témoigner de cette équivalence à 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 = ???
tel que
from . to = id
et to . from = id
?
((a -> b) -> b)
est isomorphe àa
: la seule implémentation possible estg f = f someHardcodedA
.g = const someHardcodedB
a
oub
. Logique.to f = callcc (\k -> k (Right (f (\a -> k (Left a)))))
cela fonctionnerait. (Ceci est une preuve classique valide de l'implication.)Réponses:
Cela est vrai dans la logique classique, mais pas dans la logique constructive.
Dans la logique constructive, nous n'avons pas de loi du milieu exclu , c'est-à-dire que nous ne pouvons pas commencer notre réflexion avec "soit P est vrai ou P n'est pas vrai".
Classiquement, nous raisonnons comme:
x :: P
)), alors retourLeft x
.nx :: P -> Void
fonction. Ensuiteabsurd . nx :: P -> Q
(nous pouvons piquer n'importe quel type, nous prenonsQ
) et appelezf :: (P -> Q) -> Q)
avecabsurd . nx
pour obtenir la valeur du typeQ
.Le problème, qu'il n'y a pas de fonction générale d'un type:
Pour certains types de béton, il y a, par exemple,
Bool
est habité afin que nous puissions écriremais encore une fois, en général, nous ne pouvons pas.
la source
Non, c'est impossible. Considérez le cas spécial où
Q = Void
.Either P Q
est alorsEither P Void
, qui est isomorphe àP
.Par conséquent, si nous avions un terme de fonction
nous pourrions aussi avoir un terme
Selon la correspondance Curry-Howard, ce serait une tautologie dans la logique intuitionniste :
Mais ce qui précède est l'élimination de la double négation, qui est bien connue pour être impossible à prouver dans la logique intuitionniste - d'où une contradiction. (Le fait que nous puissions le prouver dans la logique classique n'est pas pertinent.)
(Remarque finale: cela suppose que le programme Haskell se termine. Bien sûr, en utilisant une récursion infinie
undefined
, et des moyens similaires pour éviter de retourner un résultat, nous pouvons habiter n'importe quel type dans Haskell.)la source
Non, ce n'est pas possible, mais c'est un peu subtil. Le problème est que les variables de type
a
etb
sont universellement quantifiées.a
etb
sont universellement quantifiés. L'appelant choisit de quel type il s'agit, vous ne pouvez donc pas simplement créer une valeur de l'un ou l'autre type. Cela implique que vous ne pouvez pas simplement créer une valeur de typeEither a b
tout en ignorant l'argumentf
. Mais l'utilisationf
est également impossible. Sans savoir quels typesa
et quels typesb
, vous ne pouvez pas créer de valeur de typea -> b
vers laquelle passerf
. Il n'y a tout simplement pas assez d'informations disponibles lorsque les types sont universellement quantifiés.Quant à savoir pourquoi l'isomorphisme ne fonctionne pas dans Haskell - êtes-vous sûr que ces propositions sont équivalentes dans une logique intuitionniste constructive? Haskell n'implémente pas une logique déductive classique.
la source
Comme d'autres l'ont souligné, cela est impossible car nous n'avons pas la loi du milieu exclu. Permettez-moi de passer en revue un peu plus explicitement. Supposons que nous ayons
et nous avons mis
b ~ Void
. Ensuite, nous obtenonsProuvons maintenant la double négation de la loi du milieu exclu appliquée à une proposition spécifique .
Alors maintenant
lem
ne peut clairement pas exister cara
peut coder la proposition selon laquelle toute configuration de machine de Turing que je choisirai s'arrêtera.Vérifions que
lem
c'est suffisant:la source
Je n'ai aucune idée de savoir si cela est valable en termes de logique, ou ce que cela signifie pour votre équivalence, mais oui, il est possible d'écrire une telle fonction en Haskell.
Pour construire un
Either a b
, nous avons besoin d'una
ou d'uneb
valeur. Nous n'avons aucun moyen de construire unea
valeur, mais nous avons une fonction qui renvoie unb
que nous pourrions appeler. Pour ce faire, nous devons fournir une fonction qui convertit una
en unb
, mais étant donné que les types sont inconnus, nous pourrions au mieux créer une fonction qui renvoie une constanteb
. Pour obtenir cetteb
valeur, nous ne pouvons pas la construire autrement qu'avant, donc cela devient un raisonnement circulaire - et nous pouvons résoudre cela en créant simplement un point fixe :la source