Quelles sont les équivalences les plus intéressantes issues de l'isomorphisme de Curry-Howard?

97

Je suis tombé sur l' isomorphisme de Curry-Howard relativement tard dans ma vie de programmation, ce qui contribue peut-être à ce que je sois totalement fasciné par celui-ci. Cela implique que pour chaque concept de programmation, il existe un analogue précis dans la logique formelle, et vice versa. Voici une liste "de base" de ces analogies, par surprise:

program/definition        | proof
type/declaration          | proposition
inhabited type            | theorem/lemma
function                  | implication
function argument         | hypothesis/antecedent
function result           | conclusion/consequent
function application      | modus ponens
recursion                 | induction
identity function         | tautology
non-terminating function  | absurdity/contradiction
tuple                     | conjunction (and)
disjoint union            | disjunction (or)          -- corrected by Antal S-Z
parametric polymorphism   | universal quantification

Donc, à ma question: quelles sont certaines des implications les plus intéressantes / obscures de cet isomorphisme? Je ne suis pas logicien, donc je suis sûr que je n'ai fait qu'effleurer la surface avec cette liste.

Par exemple, voici quelques notions de programmation pour lesquelles je ne connais pas les noms pithy en logique:

currying                  | "((a & b) => c) iff (a => (b => c))"
scope                     | "known theory + hypotheses"

Et voici quelques concepts logiques que je n'ai pas tout à fait épinglés en termes de programmation:

primitive type?           | axiom
set of valid programs?    | theory

Éditer:

Voici quelques équivalences supplémentaires recueillies à partir des réponses:

function composition      | syllogism                -- from Apocalisp
continuation-passing      | double negation          -- from camccann
Tom Crockett
la source
fermeture ~ = ensemble d'axiomes
Apocalisp
+1 Cette question et toutes les réponses et commentaires de qualité m'ont appris plus sur CHI que ce que j'ai pu apprendre sur Internet.
Alexandre C.
24
@Paul Nathan:goto | jumping to conclusions
Joey Adams
Je pense que l'ensemble de tous les programmes valides serait un modèle
Daniil
1
fst / snd | élimination de conjonction, gauche / droite | disjonction introduction
Tony Morris

Réponses:

33

Puisque vous avez explicitement demandé les plus intéressants et les plus obscurs:

Vous pouvez étendre CH à de nombreuses logiques et formulations de logiques intéressantes pour obtenir une très grande variété de correspondances. Ici, j'ai essayé de me concentrer sur certains des plus intéressants plutôt que sur l'obscur, ainsi que sur quelques éléments fondamentaux qui ne sont pas encore apparus.

evaluation             | proof normalisation/cut-elimination
variable               | assumption
S K combinators        | axiomatic formulation of logic   
pattern matching       | left-sequent rules 
subtyping              | implicit entailment (not reflected in expressions)
intersection types     | implicit conjunction
union types            | implicit disjunction
open code              | temporal next
closed code            | necessity
effects                | possibility
reachable state        | possible world
monadic metalanguage   | lax logic
non-termination        | truth in an unobservable possible world
distributed programs   | modal logic S5/Hybrid logic
meta variables         | modal assumptions
explicit substitutions | contextual modal necessity
pi-calculus            | linear logic

EDIT: Une référence que je recommanderais à tous ceux qui souhaitent en savoir plus sur les extensions de CH:

"A Judgmental Reconstruction of Modal Logic" http://www.cs.cmu.edu/~fp/papers/mscs00.pdf - c'est un bon point de départ car il part des premiers principes et une grande partie est destinée à être accessible aux non-logiciens / théoriciens du langage. (Je suis le deuxième auteur, donc je suis partial.)

RD1
la source
merci d'avoir fourni des exemples moins triviaux (c'était vraiment l'esprit de la question initiale), même si j'admets que plusieurs d'entre eux sont au-dessus de ma tête ... les termes «nécessité» et «possibilité» sont-ils précisément définis en logique? comment se traduisent-ils en leurs équivalents informatiques?
Tom Crockett
2
Je peux signaler les articles publiés pour chacun de ces articles, afin qu'ils soient définis avec précision. La logique modale est très étudiée (depuis Aristote) et relie différents modes de vérité - "A est nécessairement vrai" signifie "dans chaque monde possible A est vrai", tandis que "A est peut-être vrai" signifie "A est vrai dans un monde possible" . Vous pouvez prouver des choses comme "(nécessairement (A -> B) et éventuellement A) -> éventuellement B". Les règles d'inférence modale donnent directement les constructions d'expression, les règles de typage et de réduction, comme d'habitude dans CH. Voir: en.wikipedia.org/wiki/Modal_logic et cs.cmu.edu/~fp/papers/mscs00.pdf
RD1
2
@pelotom: Vous voudrez peut-être en savoir plus sur d' autres types de logique . La logique classique simple n'est souvent pas utile dans ce contexte - j'ai mentionné la logique intuitionniste dans ma réponse, mais la logique modale et linéaire est encore plus "bizarre", mais aussi vraiment géniale.
CA McCann
1
Merci pour les conseils, on dirait que j'ai un peu de lecture à faire!
Tom Crockett
2
@ RD1: Vous pensez que c'est mauvais, j'ai passé tellement de temps à réfléchir dans Haskell que je dois traduire mentalement des formules de logique de prédicat en signatures de type avant qu'elles n'aient un sens. : (Sans oublier que la loi du milieu exclu et autres commence à sembler vraiment déroutante et peut-être suspecte.
CA McCann
26

Vous embrouillez un peu les choses concernant la non-terminaison. La fausseté est représentée par des types inhabités , qui par définition ne peuvent pas être sans terminaison car il n'y a rien de ce type à évaluer en premier lieu.

La non-résiliation représente une contradiction - une logique incohérente. Une logique incohérente vous permettra bien sûr de prouver quoi que ce soit , y compris la fausseté, cependant.

Ignorant les incohérences, les systèmes de types correspondent généralement à une logique intuitionniste et sont par nécessité constructivistes , ce qui signifie que certains éléments de la logique classique ne peuvent pas être exprimés directement, voire pas du tout. D'un autre côté, c'est utile, car si un type est une preuve constructive valide, alors un terme de ce type est un moyen de construire tout ce dont vous avez prouvé l'existence .

Une caractéristique majeure de la saveur constructiviste est que la double négation n'est pas équivalente à la non-négation. En fait, la négation est rarement une primitive dans un système de types, donc à la place nous pouvons la représenter comme impliquant le mensonge, par exemple, not Pdevient P -> Falsity. La double négation serait donc une fonction avec type (P -> Falsity) -> Falsity, ce qui n'est clairement pas équivalent à quelque chose de type juste P.

Cependant, il y a une tournure intéressante à ce sujet! Dans un langage à polymorphisme paramétrique, les variables de type s'étendent sur tous les types possibles, y compris les types inhabités, donc un type entièrement polymorphe tel que ∀a. a, dans un certain sens, est presque faux. Et si nous écrivions une double quasi-négation en utilisant le polymorphisme? Nous obtenons un type qui ressemble à ceci: ∀a. (P -> a) -> a. Est-ce que cela équivaut à quelque chose de type P? En fait , il suffit de l'appliquer à la fonction d'identité.

Mais à quoi ça sert? Pourquoi écrire un type comme ça? Cela signifie- t-il quelque chose en termes de programmation? Eh bien, vous pouvez le considérer comme une fonction qui a déjà quelque chose de type Pquelque part, et qui a besoin que vous lui donniez une fonction qui prend Pcomme argument, le tout étant polymorphe dans le type de résultat final. En un sens, il représente un calcul suspendu , attendant que le reste soit fourni. En ce sens, ces calculs suspendus peuvent être composés ensemble, transmis, invoqués, peu importe. Cela devrait commencer à sembler familier aux fans de certaines langues, comme Scheme ou Ruby - parce que cela signifie que la double négation correspond au style de continuation-pass, et en fait le type que j'ai donné ci-dessus est exactement la monade de continuation dans Haskell.

CA McCann
la source
Merci pour la correction, j'ai supprimé «fausseté» comme synonyme de non-résiliation. +1 pour la double négation <=> CPS!
Tom Crockett
Je ne comprends pas vraiment l'intuition de représenter ¬p comme P -> Falsity. Je comprends pourquoi cela fonctionne (¬p ≡ p → ⊥), mais je ne reçois pas la version du code. P -> ⊥devrait être habité précisément quand ce Pn'est pas le cas, non? Mais cette fonction ne devrait-elle pas toujours être habitée? Ou possible jamais, en fait, puisque vous ne pouvez pas renvoyer une instance de ? Je n'en vois pas tout à fait la conditionnalité. Quelle est l'intuition ici?
Antal Spector-Zabusky
1
@Antal SZ: L'intuition est une logique intuitionniste, bien sûr! Mais oui, écrire une telle fonction est difficile. Je vois dans votre profil que vous connaissez Haskell, alors peut-être pensez-vous aux types de données algébriques et à la correspondance de motifs? Considérez qu'un type inhabité ne doit avoir aucun constructeur et, par conséquent, rien à comparer avec un modèle. Vous auriez à écrire une "fonction" sans corps, ce qui n'est pas légal Haskell. En fait, à ma connaissance, il n'y a aucun moyen d'écrire un terme de type nié dans Haskell sans utiliser d'exceptions d'exécution ou de non-terminaison.
CA McCann
1
@Antal SZ: Par contre, si la logique équivalente est cohérente, toutes les fonctions doivent être totales, par exemple, toutes les correspondances de motifs doivent être exhaustives. Ainsi, pour écrire une fonction sans modèle, le type de paramètre ne doit avoir aucun constructeur, par exemple être inhabité. Par conséquent, une telle fonction serait légale - et donc son propre type habité - précisément et uniquement lorsque son argument est inhabité. Par conséquent, une fonction P -> Falsityéquivaut à Pêtre fausse.
CA McCann
Aha, je pense que je comprends. La version que j'avais divertie était quelque chose comme f x = x, qui serait instanciable si P = ⊥, mais ce n'était clairement pas assez générique. L'idée est donc que pour renvoyer un type sans valeur, vous n'avez pas besoin de corps; mais pour que la fonction soit définissable et totale, vous n'avez pas besoin de cas , et donc s'il Pest inhabité, tout fonctionne? C'est un peu bancal, mais je pense que je le vois. Cela semble interagir assez bizarrement avec ma définition du Xortype… Je vais devoir y réfléchir. Merci!
Antal Spector-Zabusky
15

Votre graphique n'est pas tout à fait exact; dans de nombreux cas, vous avez confondu les types et les termes.

function type              implication
function                   proof of implication
function argument          proof of hypothesis
function result            proof of conclusion
function application RULE  modus ponens
recursion                  n/a [1]
structural induction       fold (foldr for lists)
mathematical induction     fold for naturals (data N = Z | S N)
identity function          proof of A -> A, for all A
non-terminating function   n/a [2]
tuple                      normal proof of conjunction
sum                        disjunction
n/a [3]                    first-order universal quantification
parametric polymorphism    second-order universal quantification
currying                   (A,B) -> C -||- A -> (B -> C), for all A,B,C
primitive type             axiom
types of typeable terms    theory
function composition       syllogism
substitution               cut rule
value                      normal proof

[1] La logique d'un langage fonctionnel Turing-complet est incohérente. La récursivité n'a pas de correspondance dans les théories cohérentes. Dans une logique incohérente / théorie de la preuve non valable, vous pouvez l'appeler une règle qui provoque une incohérence / un défaut de validité.

[2] Encore une fois, c'est une conséquence de l'exhaustivité. Ce serait une preuve d'un anti-théorème si la logique était cohérente - donc, elle ne peut pas exister.

[3] N'existe pas dans les langages fonctionnels, car ils élident les caractéristiques logiques du premier ordre: toute quantification et paramétrisation se fait sur des formules. Si vous aviez des fonctionnalités de premier ordre, il y aurait une autre espèce que *, * -> *, etc .; le genre d'éléments du domaine du discours. Par exemple, dans Father(X,Y) :- Parent(X,Y), Male(X), Xet Yportée sur le domaine du discours (appeler Dom), et Male :: Dom -> *.

Frank Atanassow
la source
[1] - oui, j'aurais dû être plus précis. Je voulais dire "récursivité structurelle" plutôt que récursivité sans contrainte, qui, je suppose, est la même chose que "repli". [3] - il existe dans des langues à typage dépendant
Tom Crockett
[1] Le fait est que si un appel de fonction récursive (modus ponens) ne provoque pas la non-terminaison du programme, les paramètres (hypothèses) donnés à l'appel ou à l'environnement DOIVENT être différents entre ces appels. Ainsi, la récursivité applique simplement le même théorème plusieurs fois. S'il y a quelque chose de spécial, c'est généralement des nombres croissants / décroissants (pas inductif) et en vérifiant avec un cas existant (cas de base), qui correspond à - Induction mathématique en logique.
Earth Engine
J'aime vraiment ce graphique, mais je ne dirais pas "n / a", car la logique cohérente n'est pas le seul type de logique, tout comme la terminaison des programmes n'est pas le seul type de programme. Une fonction sans terminaison correspondrait à un "argument circulaire", et est une excellente illustration de l'isomorphisme de Curry-Howard: "suivre" un argument circulaire vous met dans une boucle sans fin.
Joey Adams
14
function composition      | syllogism
Apocalisp
la source
13

J'aime vraiment cette question. Je ne sais pas grand-chose, mais j'ai quelques petites choses (assisté par l'article de Wikipédia , qui contient des tableaux soignés et autres):

  1. Je pense que les types de somme / types d'union ( par exemple data Either a b = Left a | Right b ) sont équivalents à la disjonction inclusive . Et, bien que je ne connaisse pas très bien Curry-Howard, je pense que cela le démontre. Considérez la fonction suivante:

    andImpliesOr :: (a,b) -> Either a b
    andImpliesOr (a,_) = Left a
    

    Si je comprends bien les choses, le type dit que ( a  ∧  b ) → ( a  ★  b ) et la définition dit que c'est vrai, où ★ est soit inclusif, soit exclusif ou, selon ce que Eitherreprésente. Vous avez Eitherreprésentant exclusif ou, ⊕; cependant, ( a  ∧  b ) ↛ ( a  ⊕  b ). Par exemple, ⊤ ∧ ⊤ ≡ ⊤, mais ⊤ ⊕ ⊥ ≡ ⊥ et ⊤ ↛ ⊥. En d'autres termes, si a et b sont tous les deux vrais, alors l'hypothèse est vraie mais la conclusion est fausse, et donc cette implication doit être fausse. Cependant, clairement, ( a  ∧  b ) → ( a  ∨ b ), puisque si a et b sont tous les deux vrais, alors au moins un est vrai. Ainsi, si les unions discriminées sont une forme de disjonction, elles doivent être la variété inclusive. Je pense que c'est une preuve, mais je me sens plus que libre de me désabuser de cette notion.

  2. De même, vos définitions de la tautologie et de l'absurdité en tant que fonction d'identité et fonctions non terminales, respectivement, sont un peu décalées. La vraie formule est représentée par le type d'unité , qui est le type qui n'a qu'un seul élément ( data ⊤ = ⊤; souvent orthographié ()et / ou Unitdans les langages de programmation fonctionnels). Cela a du sens: puisque ce type est garanti d'être habité, et comme il n'y a qu'un seul habitant possible, cela doit être vrai. La fonction d'identité représente simplement la tautologie particulière que a  →  a .

    Votre commentaire sur les fonctions sans terminaison est, en fonction de ce que vous vouliez précisément dire, plus offensif. Curry-Howard fonctionne sur le système de types, mais la non-terminaison n'y est pas codée. Selon Wikipedia , traiter la non-terminaison est un problème, car l'ajouter produit des logiques incohérentes ( par exemple , je peux définir wrong :: a -> bpar wrong x = wrong x, et donc «prouver» que a  →  b pour tout a et b ). Si c'est ce que vous entendez par «absurdité», alors vous avez tout à fait raison. Si à la place vous vouliez dire la fausse déclaration, alors ce que vous voulez à la place est n'importe quel type inhabité, par exemple quelque chose défini pardata ⊥- c'est-à-dire un type de données sans aucun moyen de le construire. Cela garantit qu'il n'a aucune valeur du tout et qu'il doit donc être inhabité, ce qui équivaut à false. Je pense que vous pourriez probablement également l'utiliser a -> b, car si nous interdisons les fonctions sans terminaison, cela est également inhabité, mais je ne suis pas sûr à 100%.

  3. Wikipedia dit que les axiomes sont codés de deux manières différentes, selon la façon dont vous interprétez Curry-Howard: soit dans les combinateurs, soit dans les variables. Je pense que la vue combinateur signifie que les fonctions primitives qui nous sont données codent les choses que nous pouvons dire par défaut (de la même manière que modus ponens est un axiome parce que l'application de la fonction est primitive). Et je pense que la vue variable peut en fait signifier la même chose - les combinateurs, après tout, ne sont que des variables globales qui sont des fonctions particulières. Quant aux types primitifs: si j'y pense correctement, alors je pense que les types primitifs sont les entités - les objets primitifs sur lesquels nous essayons de prouver les choses.

  4. D'après ma classe de logique et de sémantique, le fait que ( a  ∧  b ) →  c  ≡  a  → ( b  →  c ) (et aussi que b  → ( a  →  c )) est appelé loi d'équivalence d'exportation, du moins en déduction naturelle preuves. Je n'ai pas remarqué à l'époque que c'était juste du curry - j'aurais aimé l'avoir, parce que c'est cool!

  5. Bien que nous ayons maintenant un moyen de représenter la disjonction inclusive , nous n'avons pas de moyen de représenter la variété exclusive. On devrait pouvoir utiliser la définition de la disjonction exclusive pour la représenter: a  ⊕  b  ≡ ( a  ∨  b ) ∧ ¬ ( a  ∧  b ). Je ne sais pas comment écrire la négation, mais je sais que ¬ p  ≡  p  → ⊥, et l'implication et le mensonge sont faciles. On devrait ainsi pouvoir représenter la disjonction exclusive par:

    data ⊥
    data Xor a b = Xor (Either a b) ((a,b) -> ⊥)
    

    Cela définit être le type vide sans valeurs, ce qui correspond à la fausseté; Xorest alors défini pour contenir à la fois ( et ) Eitherun a ou un b ( ou ) et une fonction ( implication ) de (a, b) ( et ) au type inférieur ( faux ). Cependant, je n'ai aucune idée de ce que cela signifie . ( Edit 1: Maintenant je le fais, voir le paragraphe suivant!) ( Edit 1: Oui, camccann .) Puisqu'il n'y a pas de valeurs de type (a,b) -> ⊥(y a-t-il?), Je ne peux pas comprendre ce que cela signifierait dans un programme. Quelqu'un connaît-il une meilleure façon de penser à cette définition ou à une autre?

    Edit 1: Grâce à la réponse de camccann (plus particulièrement, les commentaires qu'il a laissés dessus pour m'aider), je pense voir ce qui se passe ici. Pour construire une valeur de type Xor a b, vous devez fournir deux choses. Premièrement, un témoin de l'existence d'un élément de l'un aou bde l' autre ou comme premier argument; c'est-à-dire a Left aou a Right b. Et deuxièmement, une preuve qu'il n'y a pas d'éléments des deux types aet b- en d'autres termes, une preuve (a,b)inhabitée - comme deuxième argument. Puisque vous ne pourrez écrire une fonction qu'à partir de (a,b) -> ⊥if (a,b)est inhabité, qu'est-ce que cela signifie pour que ce soit le cas? Cela signifierait qu'une partie d'un objet de type(a,b) ne peut pas être construit; en d'autres termes, qu'au moins un, et peut-être les deux,a et bsont inhabitée aussi bien! Dans ce cas, si nous pensons à la correspondance de motifs, vous ne pourriez pas éventuellement correspondre à des motifs sur un tel tuple: en supposant que ce bsoit inhabité, qu'écririons-nous qui pourrait correspondre à la deuxième partie de ce tuple? Ainsi, nous ne pouvons pas faire de correspondance de motif avec lui, ce qui peut vous aider à comprendre pourquoi cela le rend inhabité. Maintenant, le seul moyen d'avoir une fonction totale qui ne prend aucun argument (comme celui-ci doit, car il (a,b)est inhabité) est que le résultat soit également d'un type inhabité - si nous y réfléchissons du point de vue de la correspondance de motifs, cela signifie que même si la fonction n'a pas de cas, il n'y a pas de corps possible il pourrait avoir l'un ou l'autre, et donc tout va bien.

Une grande partie de cela me fait penser à haute voix / prouver (espérons-le) des choses à la volée, mais j'espère que c'est utile. Je recommande vraiment l'article Wikipédia ; Je ne l'ai pas lu en détail, mais ses tableaux sont un très bon résumé et il est très complet.

Antal Spector-Zabusky
la source
1
+1 pour avoir souligné que Soit est inclusif-ou. Notez que (Soit aa) est un théorème (pour tout a).
Apocalisp
Question re. 2 (b): quelle est la différence entre un type de fonction dont le seul habitant est non-terminal et un type de fonction inhabité? Par exemple, si je déclarais un type B sans constructeur, puis définissais une fonction A-> B comme ceci: fun (a: A): B: = f (a) cela vérifierait le type dans beaucoup de langues, même si c'est impossible de jamais retourner un B. Donc la fonction est "habitée" dans un sens, mais son "habitant" est absurde ... donc elle n'est pas vraiment habitée du tout. J'espère que cela a un sens :)
Tom Crockett
3
Les bas ne sont pas des preuves. «Il est absurde et impossible de supposer que l'inconnaissable et l'indéterminé doivent contenir et déterminer. - Aristoteles
Apocalisp
2
@Tom: Juste pour faire ressortir le point sur la non-terminaison, si la logique est cohérente, tous les programmes se terminent . La non-terminaison ne se produit que dans les systèmes de types représentant des logiques incohérentes, ou de manière équivalente, des systèmes de types pour les langages Turing-complets.
CA McCann
1
Apocalisp: Either a a ne devrait pas tout à fait être un théorème: Either ⊥ ⊥est toujours inhabité. Tom: Comme l'a dit camccann, la cohérence implique la résiliation. Ainsi, un système de types cohérent ne vous permettra pas d'exprimer f :: a -> b, et donc le type serait inhabité; un système de type incohérent aurait un habitant pour le type, mais un qui ne se terminerait pas. camccann: Y a-t-il des systèmes de types incohérents qui ne sont pas complets de Turing, occupant un point intermédiaire sur la hiérarchie? Ou est-ce que cette dernière étape (ajouter une récursion générale ou autre) équivaut précisément à l'incohérence?
Antal Spector-Zabusky
12

En voici une un peu obscure dont je suis surpris de ne pas avoir été évoquée plus tôt: la programmation réactive fonctionnelle "classique" correspond à la logique temporelle.

Bien sûr, à moins que vous ne soyez un philosophe, mathématicien ou programmeur fonctionnel obsessionnel, cela soulève probablement plusieurs autres questions.

Alors, tout d'abord: qu'est-ce que la programmation réactive fonctionnelle? C'est une façon déclarative de travailler avec des valeurs variant dans le temps . Ceci est utile pour écrire des éléments tels que les interfaces utilisateur, car les entrées de l'utilisateur sont des valeurs qui varient dans le temps. Le FRP "classique" a deux types de données de base: les événements et les comportements.

Les événements représentent des valeurs qui n'existent qu'à des moments discrets. Les frappes au clavier sont un bon exemple: vous pouvez considérer les entrées du clavier comme un caractère à un moment donné. Chaque pression de touche est alors juste une paire avec le caractère de la touche et l'heure à laquelle elle a été enfoncée.

Les comportements sont des valeurs qui existent constamment mais qui peuvent changer continuellement. La position de la souris est un excellent exemple: c'est juste un comportement des coordonnées x, y. Après tout, la souris a toujours une position et, conceptuellement, cette position change continuellement lorsque vous déplacez la souris. Après tout, déplacer la souris est une simple action prolongée, pas un tas d'étapes discrètes.

Et qu'est-ce que la logique temporelle? À juste titre, il s'agit d'un ensemble de règles logiques pour traiter des propositions quantifiées au fil du temps. Essentiellement, il étend la logique normale du premier ordre avec deux quantificateurs: □ et ◇. Le premier signifie "toujours": lisez □ φ comme "φ tient toujours". Le second est "éventuellement": ◇ φ signifie que "φ finira par tenir". Il s'agit d'un type particulier de logique modale . Les deux lois suivantes relient les quantificateurs:

□φ ⇔ ¬◇¬φ
◇φ ⇔ ¬□¬φ

Donc □ et ◇ sont duels l'un à l'autre de la même manière que ∀ et ∃.

Ces deux quantificateurs correspondent aux deux types en FRP. En particulier, □ correspond à des comportements et ◇ correspond à des événements. Si nous réfléchissons à la façon dont ces types sont habités, cela devrait avoir du sens: un comportement est habité à chaque instant possible, alors qu'un événement ne se produit qu'une seule fois.

Tikhon Jelvis
la source
8

Lié à la relation entre continuations et double négation, le type d'appel / cc est la loi de Peirce http://en.wikipedia.org/wiki/Call-with-current-continuation

CH est généralement indiqué comme une correspondance entre la logique intuitionniste et les programmes. Cependant si on ajoute l'opérateur call-with-current-continuation (callCC) (dont le type correspond à la loi de Peirce), on obtient une correspondance entre la logique classique et les programmes avec callCC.

James Iry
la source
4

Bien que ce ne soit pas un simple isomorphisme, cette discussion sur le LEM constructif est un résultat très intéressant. En particulier, dans la section des conclusions, Oleg Kannedov explique comment l'utilisation de monades pour obtenir l'élimination de la double négation dans une logique constructive est analogue à la distinction des propositions calculables par calcul (pour lesquelles LEM est valide dans un cadre constructif) de toutes les propositions. L'idée que les monades capturent les effets de calcul est ancienne, mais cette instance de l'isomorphisme de Curry-Howard aide à la mettre en perspective et à comprendre ce que la double négation "signifie" réellement.

Wren Romano
la source
4

Le support des continuations de première classe vous permet d'exprimer $ P \ lor \ neg P $. L'astuce est basée sur le fait que ne pas appeler la continuation et sortir avec une expression équivaut à appeler la continuation avec cette même expression.

Pour une vue plus détaillée, veuillez consulter: http://www.cs.cmu.edu/~rwh/courses/logic/www-old/handouts/callcc.pdf

Daniil
la source
Merci pour cet aperçu!
paulotorrens
4
2-continuation           | Sheffer stoke
n-continuation language  | Existential graph
Recursion                | Mathematical Induction

Une chose qui est importante, mais qui n'a pas encore été étudiée, est la relation entre la 2 continuation (continuations qui prend 2 paramètres) et l' AVC de Sheffer . Dans la logique classique, Sheffer stroke peut former un système logique complet par lui-même (plus certains concepts non-opérateurs). Ce qui signifie que le familier and, or, notpeut être mis en œuvre en utilisant uniquement le stoke Sheffer ounand .

C'est un fait important de sa correspondance de type de programmation car il indique qu'un seul combinateur de type peut être utilisé pour former tous les autres types.

La signature de type d'une 2-continuation est (a,b) -> Void. Par cette implémentation, nous pouvons définir 1-continuation (continuations normales) comme (a,a)-> Void, type de produit comme ((a,b)->Void,(a,b)->Void)->Void, type de somme comme((a,a)->Void,(b,b)->Void)->Void . Cela nous donne une impression impressionnante de sa puissance d'expressivité.

Si nous creusons plus loin, nous découvrirons que le graphe existentiel de Piece est équivalent à un langage dont le seul type de données est n-continuation, mais je n'ai vu aucun langage existant sous cette forme. Donc, inventer un pourrait être intéressant, je pense.

Moteur de la Terre
la source