Quali sono le equivalenze più interessanti derivanti dall'isomorfismo di Curry-Howard?


97

Mi sono imbattuto nell'isomorfismo di Curry-Howard relativamente tardi nella mia vita di programmazione, e forse questo contribuisce a farmi essere completamente affascinato da esso. Implica che per ogni concetto di programmazione esista un preciso analogo nella logica formale, e viceversa. Ecco un elenco "di base" di tali analogie, in cima alla mia testa:

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

Quindi, alla mia domanda: quali sono alcune delle implicazioni più interessanti / oscure di questo isomorfismo? Non sono un logico, quindi sono sicuro di aver solo scalfito la superficie con questo elenco.

Ad esempio, ecco alcune nozioni di programmazione per le quali non sono a conoscenza di nomi concisi nella logica:

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

E qui ci sono alcuni concetti logici che non ho ancora definito in termini di programmazione:

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

Modificare:

Ecco alcune altre equivalenze raccolte dalle risposte:

function composition      | syllogism                -- from Apocalisp
continuation-passing      | double negation          -- from camccann

chiusura ~ = set di assiomi
Apocalisp

+1 Questa domanda e tutte le risposte e i commenti di qualità mi hanno insegnato di più sul CHI di quanto potessi imparare tramite Internet.
Alexandre C.

24
@ Paul Nathan:goto | jumping to conclusions
Joey Adams

Penso che l'insieme di tutti i programmi validi sarebbe un modello
Daniil

1
fst / snd | eliminazione congiunzione, sinistra / destra | introduzione alla disgiunzione
Tony Morris

Risposte:


33

Dal momento che hai chiesto esplicitamente quelli più interessanti e oscuri:

È possibile estendere CH a molte logiche e formulazioni di logiche interessanti per ottenere una varietà di corrispondenze davvero ampia. Qui ho cercato di concentrarmi su alcuni di quelli più interessanti piuttosto che su quelli oscuri, più un paio di quelli fondamentali che non sono ancora emersi.

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: un riferimento che consiglierei a chiunque sia interessato a saperne di più sulle estensioni di CH:

"A Judgmental Reconstruction of Modal Logic" http://www.cs.cmu.edu/~fp/papers/mscs00.pdf - questo è un ottimo punto di partenza perché parte dai principi primi e gran parte di esso mira ad essere accessibile a non logici / teorici del linguaggio. (Sono il secondo autore però, quindi sono di parte.)


grazie per aver fornito alcuni esempi meno banali (questo era davvero lo spirito della domanda originale), anche se ammetto che molti di questi sono sopra la mia testa ... i termini "necessità" e "possibilità" sono definiti con precisione nella logica? come si traducono nei loro equivalenti computazionali?
Tom Crockett

2
Posso indicare documenti pubblicati per ciascuno di questi, quindi sono definiti con precisione. La logica modale è molto studiata (da Aristotele) e mette in relazione diversi modi di verità - "A è necessariamente vero" significa "in ogni mondo possibile A è vero", mentre "A è forse vero" significa "A è vero in un mondo possibile" . Puoi provare cose come "(necessariamente (A -> B) e possibilmente A) -> possibilmente B". Le regole di inferenza modale producono direttamente i costrutti di espressione, le regole di tipizzazione e di riduzione, come al solito in CH. Vedi: en.wikipedia.org/wiki/Modal_logic e cs.cmu.edu/~fp/papers/mscs00.pdf
RD1

2
@pelotom: potresti voler leggere un po 'di altri tipi di logica . La logica classica semplice spesso non è utile in questo contesto - ho menzionato la logica intuizionistica nella mia risposta, ma la logica modale e lineare sono anche "più strane", ma anche davvero fantastiche.
CA McCann

1
Grazie per i suggerimenti, sembra che abbia un po 'di lettura da fare!
Tom Crockett

2
@ RD1: Pensi che sia un male, ho passato così tanto tempo a pensare in Haskell che devo tradurre mentalmente le formule della logica dei predicati in firme di tipo prima che abbiano senso. :( Per non parlare del fatto che la legge del centro escluso e simili inizia a sembrare davvero confusa e forse sospetta.
CA McCann

26

Stai un po 'confondendo le cose riguardo alla non terminazione. La falsità è rappresentata da tipi disabitati , che per definizione non possono essere infiniti perché non c'è nulla di quel tipo da valutare in primo luogo.

La mancata risoluzione rappresenta una contraddizione, una logica incoerente. Una logica incoerente ti consentirà ovviamente di provare qualsiasi cosa , inclusa la falsità, comunque.

Ignorando le incongruenze, i sistemi di tipo corrispondono tipicamente a una logica intuizionista e sono necessariamente costruttivisti , il che significa che alcuni pezzi di logica classica non possono essere espressi direttamente, se non del tutto. D'altra parte questo è utile, perché se un tipo è una valida dimostrazione costruttiva, allora un termine di quel tipo è un mezzo per costruire qualunque cosa tu abbia dimostrato l'esistenza .

Una delle principali caratteristiche del gusto costruttivista è che la doppia negazione non è equivalente alla non negazione. In effetti, la negazione è raramente una primitiva in un sistema di tipi, così invece possiamo rappresentarla come implicante la falsità, ad esempio, not Pdiventa P -> Falsity. La doppia negazione sarebbe quindi una funzione con tipo (P -> Falsity) -> Falsity, che chiaramente non è equivalente a qualcosa di solo tipo P.

Tuttavia, c'è una svolta interessante in questo! In un linguaggio con polimorfismo parametrico, le variabili di tipo spaziano su tutti i tipi possibili, compresi quelli disabitati, quindi un tipo completamente polimorfico come ∀a. aè, in un certo senso, quasi falso. E se scriviamo una doppia quasi negazione usando il polimorfismo? Otteniamo un tipo che assomiglia a questo: ∀a. (P -> a) -> a. È equivalente a qualcosa di tipo P? In effetti lo è , basta applicarlo alla funzione di identità.

Ma qual è il punto? Perché scrivere un tipo così? Lo fa media nulla in termini di programmazione? Bene, puoi pensarla come una funzione che ha già qualcosa di tipo Pda qualche parte, e ha bisogno che tu gli dia una funzione che prende Pcome argomento, con l'intera cosa polimorfa nel tipo di risultato finale. In un certo senso, rappresenta un calcolo sospeso , in attesa che venga fornito il resto. In questo senso, questi calcoli sospesi possono essere composti insieme, passati, invocati, qualunque cosa. Questo dovrebbe iniziare a suonare familiare ai fan di alcune lingue, come Scheme o Ruby, perché ciò che significa è che la doppia negazione corrisponde allo stile di continuazione passante, e infatti il ​​tipo che ho dato sopra è esattamente la monade di continuazione in Haskell.


Grazie per la correzione, ho rimosso "falsità" come sinonimo di non terminazione. +1 per doppia negazione <=> CPS!
Tom Crockett

Non capisco bene l'intuizione dietro la rappresentazione di ¬p as P -> Falsity. Capisco perché funziona (¬p ≡ p → ⊥), ma non ho la versione del codice. P -> ⊥dovrebbe essere abitato proprio quando Pnon lo è, giusto? Ma questa funzione non dovrebbe essere sempre abitata? O possibile mai, in realtà, poiché non puoi restituire un'istanza di ? Non ne vedo abbastanza la condizionalità. Qual è l'intuizione qui?
Antal Spector-Zabusky

1
@Antal SZ: L'intuizione è logica intuizionista, ovviamente! Ma sì, in realtà scrivere una tale funzione è difficile. Vedo nel tuo profilo che conosci Haskell, quindi forse stai pensando ai tipi di dati algebrici e al pattern matching? Considera che un tipo disabitato non deve avere costruttori e, quindi, niente con cui trovare una corrispondenza per pattern. Dovresti scrivere una "funzione" senza corpo, che non è Haskell legale. In effetti, per quanto ne so, non c'è modo di scrivere un termine di tipo negato in Haskell senza utilizzare eccezioni di runtime o non terminazione.
CA McCann

1
@Antal SZ: D'altra parte, se la logica equivalente è coerente, tutte le funzioni devono essere totali, ad esempio, tutti i pattern matching devono essere esaustivi. Quindi, per scrivere una funzione senza pattern, il tipo di parametro non deve avere costruttori, ad esempio, essere disabitato. Pertanto, una tale funzione sarebbe legale - e quindi abitata nel suo stesso tipo - proprio e solo quando il suo argomento è disabitato. Quindi, una funzione P -> Falsityequivale ad Pessere falsa.
CA McCann

Aha, penso di aver capito. La versione che stavo intrattenendo era qualcosa del genere f x = x, che sarebbe stata istanziabile se P = ⊥e solo così , ma chiaramente non era abbastanza generica. Quindi l'idea è che per restituire un tipo senza valore, non è necessario alcun corpo; ma perché la funzione sia definibile e totale non servono casi e quindi se Pè disabitata tutto funziona? È un po 'traballante, ma penso di vederlo. Questo sembra interagire in modo piuttosto strano con la mia definizione del Xortipo ... ci devo pensare. Grazie!
Antal Spector-Zabusky

15

Il tuo grafico non è del tutto corretto; in molti casi hai confuso i tipi con i termini.

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 logica per un linguaggio funzionale completo di Turing è incoerente. La ricorsione non ha corrispondenza nelle teorie coerenti. In una logica incoerente / teoria della dimostrazione non corretta potresti chiamarla una regola che causa incoerenza / mancanza di solidità.

[2] Di nuovo, questa è una conseguenza della completezza. Questa sarebbe una prova di un anti-teorema se la logica fosse coerente - quindi, non può esistere.

[3] Non esiste nei linguaggi funzionali, poiché elidono caratteristiche logiche del primo ordine: tutta la quantificazione e la parametrizzazione vengono eseguite su formule. Se tu avessi le caratteristiche del primo ordine, non ci sarebbe una specie diversa *, * -> *ecc .; il tipo di elementi del dominio del discorso. Ad esempio, in Father(X,Y) :- Parent(X,Y), Male(X), Xand Yrange over the domain of speech (call it Dom), and Male :: Dom -> *.


[1] - sì, avrei dovuto essere più specifico. Intendevo "ricorsione strutturale" piuttosto che ricorsione non vincolata, che immagino sia la stessa di "piega". [3] - esiste nelle lingue tipizzate in modo dipendente
Tom Crockett

[1] Il fatto è che se una chiamata di funzione di ricorsione (modus ponens) non fa sì che il programma non sia terminato, i parametri (ipotesi) dati alla chiamata o all'ambiente DEVONO essere diversi tra quelle chiamate. Quindi, la ricorsione sta semplicemente applicando lo stesso teorema più volte. Se c'è qualcosa di speciale, di solito è un numero crescente / decrescente (passo induttivo) e verifica con un caso esistente (caso base), che corrisponde a - Induzione matematica nella logica.
Earth Engine

Mi piace molto questo grafico, ma non direi "n / a", poiché la logica coerente non è l'unico tipo di logica, così come la terminazione dei programmi non è l'unico tipo di programma. Una funzione non terminante corrisponderebbe a un "argomento circolare" ed è un'eccellente illustrazione dell'isomorfismo di Curry-Howard: "seguire" un argomento circolare ti mette in un ciclo infinito.
Joey Adams


13

Mi piace molto questa domanda. Non ne so molto, ma ho alcune cose (assistito dall'articolo di Wikipedia , che ha alcune tabelle pulite e simili):

  1. Penso che i tipi di somma / tipi di unione ( ad esempio data Either a b = Left a | Right b ) siano equivalenti alla disgiunzione inclusiva . E anche se non conosco molto bene Curry-Howard, penso che questo lo dimostri. Considera la seguente funzione:

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

    Se capisco le cose correttamente, il tipo dice che ( a  ∧  b ) → ( a  ★  b ) e la definizione dice che questo è vero, dove ★ è o inclusivo o esclusivo o, a seconda di quale Eitherrappresenta. Hai una Eitherrappresentanza esclusiva o, ⊕; tuttavia, ( a  ∧  b ) ↛ ( a  ⊕  b ). Ad esempio, ⊤ ∧ ⊤ ≡ ⊤, ma ⊤ ⊕ ⊥ ≡ ⊥ e ⊤ ↛ ⊥. In altre parole, se sia a che b sono vere, allora l'ipotesi è vera ma la conclusione è falsa, e quindi questa implicazione deve essere falsa. Tuttavia, chiaramente, ( a  ∧  b ) → ( a  ∨ b ), poiché se sia a che b sono veri, allora almeno uno è vero. Quindi, se le unioni discriminate sono una qualche forma di disgiunzione, devono essere la varietà inclusiva. Penso che questo sia una prova, ma sentiti più che libero di disilludermi di questa nozione.

  2. Allo stesso modo, le tue definizioni di tautologia e assurdità come funzione di identità e funzioni non terminanti, rispettivamente, sono un po 'sbagliate. La vera formula è rappresentata dal tipo di unità , che è il tipo che ha un solo elemento ( data ⊤ = ⊤; spesso scritto ()e / o Unitin linguaggi di programmazione funzionale). Questo ha senso: poiché è garantito che quella tipologia sia abitata, e poiché c'è un solo possibile abitante, deve essere vero. La funzione identità rappresenta solo la particolare tautologia che a  →  a .

    Il tuo commento sulle funzioni non terminanti è, a seconda di cosa intendevi precisamente, di più. Curry-Howard funziona sul sistema dei tipi, ma la non terminazione non è codificata lì. Secondo Wikipedia , relativa alla non-terminazione è un problema, come l'aggiunta produce logiche incoerenti ( ad esempio , posso definire wrong :: a -> bda wrong x = wrong x, e quindi “dimostrare” che un  →  b per ogni una e b ). Se questo è ciò che intendevi per "assurdità", allora hai esattamente ragione. Se invece intendevi l'affermazione falsa, allora quello che vuoi invece è un qualsiasi tipo disabitato, ad esempio qualcosa definito dadata ⊥- cioè, un tipo di dati senza alcun modo per costruirlo. Ciò garantisce che non abbia alcun valore e quindi deve essere disabitato, il che equivale a false. Penso che probabilmente potresti anche usare a -> b, poiché se proibiamo le funzioni non di terminazione, anche questa è disabitata, ma non ne sono sicuro al 100%.

  3. Wikipedia dice che gli assiomi sono codificati in due modi diversi, a seconda di come interpreti Curry-Howard: o nei combinatori o nelle variabili. Penso che la vista combinatore significhi che le funzioni primitive che ci vengono fornite codificano le cose che possiamo dire per impostazione predefinita (simile al modo in cui il modus ponens è un assioma perché l'applicazione della funzione è primitiva). E penso che la vista variabile possa effettivamente significare la stessa cosa: i combinatori, dopo tutto, sono solo variabili globali che sono funzioni particolari. Per quanto riguarda i tipi primitivi: se ci penso correttamente, penso che i tipi primitivi siano le entità, gli oggetti primitivi di cui stiamo cercando di dimostrare le cose.

  4. Secondo il mio corso di logica e semantica, il fatto che ( a  ∧  b ) →  c  ≡  a  → ( b  →  c ) (e anche che b  → ( a  →  c )) è chiamato legge di equivalenza delle esportazioni, almeno in deduzione naturale prove. All'epoca non avevo notato che si trattava solo di curry, vorrei averlo fatto, perché è fantastico!

  5. Mentre ora abbiamo un modo per rappresentare la disgiunzione inclusiva , non abbiamo un modo per rappresentare la varietà esclusiva. Dovremmo essere in grado di utilizzare la definizione di disgiunzione esclusiva per rappresentarla: a  ⊕  b  ≡ ( a  ∨  b ) ∧ ¬ ( a  ∧  b ). Non so come scrivere la negazione, ma so che ¬ p  ≡  p  → ⊥, e sia l'implicazione che la falsità sono facili. Dovremmo quindi poter rappresentare la disgiunzione esclusiva mediante:

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

    Questo definisce essere il tipo vuoto senza valori, che corrisponde alla falsità; Xorviene quindi definito per contenere sia ( e ) Eitherun a o un b ( o ) e una funzione ( implicazione ) da (a, b) ( e ) al tipo inferiore ( falso ). Tuttavia, non ho idea di cosa significhi . ( Modifica 1: ora lo faccio, vedi il paragrafo successivo!) Poiché non ci sono valori di tipo (a,b) -> ⊥(ci sono?), Non riesco a capire cosa significherebbe in un programma. Qualcuno conosce un modo migliore per pensare a questa definizione oa un'altra? ( Modifica 1: Sì, camccann .)

    Modifica 1: grazie alla risposta di camccann (in particolare, i commenti che ha lasciato per aiutarmi), penso di vedere cosa sta succedendo qui. Per costruire un valore di tipo Xor a b, devi fornire due cose. Primo, un testimone dell'esistenza di un elemento di uno ao bcome primo argomento; cioè a Left ao a Right b. E secondo, una prova che non ci sono elementi di entrambi i tipi ae b- in altre parole, una prova che (a,b)è disabitata - come secondo argomento. Dato che sarai in grado di scrivere una funzione solo da (a,b) -> ⊥if (a,b)è disabitata, cosa significa che sia così? Ciò significherebbe che una parte di un oggetto di tipo(a,b)non poteva essere costruito; in altre parole, che almeno uno, e forse entrambi, ae anche loro bsono disabitati! In questo caso, se stiamo pensando al pattern matching, non potresti possibilmente pattern-match su una tale tupla: supponendo che bsia disabitata, cosa scriveremmo che potrebbe corrispondere alla seconda parte di quella tupla? Pertanto, non possiamo combinarlo con modelli, il che potrebbe aiutarti a capire perché questo lo rende disabitato. Ora, l'unico modo per avere una funzione totale che non richiede argomenti (come questa deve essere, poiché (a,b)è disabitata) è che anche il risultato sia di tipo disabitato - se stiamo pensando a questo da una prospettiva di corrispondenza dei modelli, questo significa che anche se la funzione non ha casi, non esiste un corpo possibile potrebbe avere entrambi, quindi va tutto bene.

Molto di questo sono io che penso ad alta voce / provo (si spera) le cose al volo, ma spero che sia utile. Consiglio vivamente l'articolo di Wikipedia ; Non l'ho letto in alcun dettaglio, ma le sue tabelle sono un riassunto davvero carino ed è molto completo.


1
+1 per aver sottolineato che O è inclusivo o. Nota che (O aa) è un teorema (per tutti a).
Apocalisp

Domanda re. 2 (b): qual è la differenza tra un tipo di funzione il cui unico abitante è non terminante e un tipo di funzione disabitato? Ad esempio, se dichiarassi un tipo B senza costruttori, definissi una funzione A-> B in questo modo: fun (a: A): B: = f (a) questo verrebbe tipizzato in molte lingue, anche se è impossibile mai restituire una B. Quindi la funzione è "abitata" in un certo senso, ma il suo "abitante" è assurdo ... quindi non è per niente abitata. Spero che questo abbia un senso :)
Tom Crockett,

3
I fondoschiena non sono prove. "È assurdo e impossibile supporre che l'inconoscibile e l'indeterminato debbano contenere e determinare." - Aristoteles
Apocalisp

2
@ Tom: Giusto per portare a casa il punto sulla mancata interruzione, se la logica è coerente, tutti i programmi terminano . La mancata terminazione si verifica solo nei sistemi di tipi che rappresentano logiche incoerenti o, equivalentemente, sistemi di tipi per linguaggi completi di Turing.
CA McCann

1
Apocalisp: Either a a non dovrebbe essere proprio un teorema: Either ⊥ ⊥è ancora disabitato. Tom: Come ha detto Camccann, la coerenza implica la terminazione. Pertanto, un sistema di tipi coerente non ti consentirà di esprimere f :: a -> b, e quindi il tipo sarebbe disabitato; un sistema di tipi incoerente avrebbe un abitante per il tipo, ma uno che non terminerebbe. camccann: Esistono sistemi di tipo incoerenti che non sono completi di Turing, occupando un punto intermedio nella gerarchia? O quell'ultimo passaggio (aggiunta della ricorsione generale o altro) è esattamente equivalente all'inconsistenza?
Antal Spector-Zabusky

12

Eccone uno leggermente oscuro che mi sorprende non sia stato sollevato prima: la programmazione reattiva funzionale "classica" corrisponde alla logica temporale.

Ovviamente, a meno che tu non sia un filosofo, un matematico o un programmatore funzionale ossessivo, questo probabilmente solleva molte altre domande.

Quindi, prima di tutto: cos'è la programmazione reattiva funzionale? È un modo dichiarativo per lavorare con valori variabili nel tempo . Questo è utile per scrivere cose come le interfacce utente perché gli input dell'utente sono valori che variano nel tempo. FRP "classico" ha due tipi di dati di base: eventi e comportamenti.

Gli eventi rappresentano valori che esistono solo in momenti discreti. Le sequenze di tasti sono un ottimo esempio: puoi pensare agli input dalla tastiera come a un carattere in un dato momento. Ogni pressione di un tasto è quindi solo una coppia con il carattere del tasto e l'ora in cui è stato premuto.

I comportamenti sono valori che esistono costantemente ma possono cambiare continuamente. La posizione del mouse è un ottimo esempio: è solo un comportamento delle coordinate x, y. Dopo tutto, il mouse ha sempre una posizione e, concettualmente, questa posizione cambia continuamente mentre si sposta il mouse. Dopotutto, spostare il mouse è una singola azione prolungata, non un mucchio di passaggi discreti.

E cos'è la logica temporale? In modo abbastanza appropriato, è un insieme di regole logiche per trattare proposizioni quantificate nel tempo. Essenzialmente, estende la normale logica del primo ordine con due quantificatori: □ e ◇. Il primo significa "sempre": leggi □ φ come "φ vale sempre". Il secondo è "alla fine": ◇ φ significa che "φ alla fine manterrà". Questo è un tipo particolare di logica modale . Le due leggi seguenti riguardano i quantificatori:

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

Quindi □ e ◇ sono duali tra loro allo stesso modo di ∀ e ∃.

Questi due quantificatori corrispondono ai due tipi in FRP. In particolare, □ corrisponde a comportamenti e ◇ corrisponde a eventi. Se pensiamo a come sono abitate queste tipologie, dovrebbe avere un senso: un comportamento è abitato in ogni momento possibile, mentre un evento accade solo una volta.


8

In relazione al rapporto tra continuazioni e doppia negazione, il tipo di chiamata / cc è la legge di Peirce http://en.wikipedia.org/wiki/Call-with-current-continuation

CH è solitamente indicato come corrispondenza tra logica intuizionistica e programmi. Tuttavia se aggiungiamo l'operatore call-with-current-continuation (callCC) (il cui tipo corrisponde alla legge di Peirce), otteniamo una corrispondenza tra logica classica e programmi con callCC.


4

Sebbene non sia un semplice isomorfismo, questa discussione sul LEM costruttivo è un risultato molto interessante. In particolare, nella sezione conclusiva, Oleg Kiselyov discute come l'uso delle monadi per ottenere l'eliminazione della doppia negazione in una logica costruttiva sia analogo alla distinzione di proposizioni decidibili computazionalmente (per le quali LEM è valido in un contesto costruttivo) da tutte le proposizioni. L'idea che le monadi catturino effetti computazionali è vecchia, ma questa istanza dell'isomorfismo di Curry-Howard aiuta a metterla in prospettiva e aiuta a capire cosa "significa" realmente la doppia negazione.



4
2-continuation           | Sheffer stoke
n-continuation language  | Existential graph
Recursion                | Mathematical Induction

Una cosa importante, ma non ancora indagata, è la relazione tra 2 continuazioni (continuazioni che richiedono 2 parametri) e ictus di Sheffer . Nella logica classica, il tratto di Sheffer può formare da solo un sistema logico completo (più alcuni concetti non operatori). Il che significa che il familiare and, or, notpuò essere implementato usando solo la stoke Sheffer onand .

Questo è un fatto importante della sua corrispondenza del tipo di programmazione perché suggerisce che un unico combinatore di tipo può essere utilizzato per formare tutti gli altri tipi.

La firma del tipo di una continuazione 2 è (a,b) -> Void. Con questa implementazione possiamo definire 1-continuation (continuazioni normali) come (a,a)-> Void, product type as ((a,b)->Void,(a,b)->Void)->Void, sum type as((a,a)->Void,(b,b)->Void)->Void . Questo ci dà un'impressionante potenza espressiva.

Se approfondiamo, scopriremo che il grafo esistenziale di Piece è equivalente a una lingua con l'unico tipo di dati è n-continuation, ma non ho visto alcun linguaggio esistente in questa forma. Quindi inventarne uno potrebbe essere interessante, credo.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.