Curry-Howard e programmi da prove non costruttive


29

Questa è una domanda di follow-up a

Qual è la differenza tra prove e programmi (o tra proposizioni e tipi)?

Quale programma corrisponderebbe a una dimostrazione non costruttiva (classica) della forma k T(e,k)¬k T(e,k) ? (Supponiamo che T sia una relazione decidibile interessante, ad esempio e -th TM non si ferma in k passi.)

(ps: sto postando questa domanda in parte perché sono interessato a saperne di più su ciò che Neel intende per " la traduzione Godel-Gentzen è una trasformazione che passa di seguito" nel suo commento .)


2
Risposta parziale a pagina 2 di queste note di lezione . È un po 'enigmatico; Proverò a scavare qualcosa di più completo.
Dave Clarke

Mi ci vuole un po 'più del previsto per scrivere la mia risposta, dal momento che ho fatto l'errore di decidere di provare le cose che sapevo piuttosto che affermarle. :)
Neel Krishnaswami il

1
La JSL più recente aveva questo articolo . L'essenza è che il contenuto computazionale delle prove classiche può dipendere fortemente da come hai scelto di estrarlo. Non l'ho ancora digerito, ma ho pensato di buttarlo lì.
Mark Reitblatt

Ma hai specificato che T è una relazione decidibile , quindi ne consegue che ci sono prove costruttive della tua proposizione. La logica classica è un sottoinsieme della logica intuizionista e hai specificato che T appartiene a quel sottoinsieme chiamandolo decidibile.
scricciolo romano

wren, questo è quello che ho pensato anche all'inizio! Ma la proposizione P nell'esempio P \ / ~ P nella domanda se effettivamente quantificata su tutto k, e questa quantificazione di T non è necessariamente decidibile.
jbapple

Risposte:


25

Questa è una domanda interessante. Ovviamente non ci si può aspettare di avere un programma che decida per ogni se k T ( e , k ) valga o meno, poiché ciò determinerebbe il problema dell'arresto. Come già accennato, esistono diversi modi per interpretare le prove in modo computazionale: estensioni di Curry-Howard, realizzabilità, dialettica e così via. Ma tutti interpreterebbero computazionalmente il teorema che hai citato più o meno nel modo seguente.ekT(e,k)

Per semplicità considera l'equivalente teorema classico

(1) ij(¬T(e,j)¬T(e,i))

Questo è (costruttivamente) equivalente a quello menzionato perché dato possiamo decidere se k T ( e , k ) vale o meno semplicemente controllando il valore di ¬ T ( e , i ) . Se ¬ T ( e , i ) vale quindi i ¬ T ( e , i ) e quindi ¬ i T ( e , i ) . Se d'altra parteikT(e,k)¬T(e,i)¬T(e,i)i¬T(e,i)¬iT(e,i) non regge quindi da (1) abbiamoj ( ¬ T ( e , j ) ) che implicaj T ( e , j ) .¬T(e,i)j(¬T(e,j))jT(e,j)

Ora, di nuovo, non possiamo calcolare in (1) per ogni data e perché risolveremmo nuovamente il problema di Halting. Ciò che farebbero tutte le interpretazioni sopra menzionate è guardare al teorema equivalenteie

(2) fi(¬T(e,f(i))¬T(e,i))

La funzione è chiamata funzione Herbrand. Cerca di calcolare un contro esempio j per ogni dato testimone potenziale i . È chiaro che (1) e (2) sono equivalenti. Da sinistra a destra questo è costruttivo, basta prendere i = i in (2), dove i è il presunto testimone di (1). Da destra a sinistra bisogna ragionare in modo classico. Assumere (1) non era vero. Poi,fjii=ii

(3) ij¬(¬T(e,j)¬T(e,i))

Lascia che sia una funzione testimone di questo, cioèf

(4) i¬(¬T(e,f(i))¬T(e,i))

Ora, prendi in (2) e abbiamo ( ¬ T ( e , f ( i ) ) ¬ T ( e , i ) ) , per alcuni i . Ma prendendo i = i in (4) otteniamo la negazione di ciò, contraddizione. Quindi (2) implica (1).f=f(¬T(e,f(i))¬T(e,i))ii=i

Quindi, abbiamo che (1) e (2) sono classicamente equivalenti. Ma la cosa interessante è che (2) ha ora una testimonianza costruttiva molto semplice. Prendi semplicemente se T ( e , f ( 0 ) ) non regge, perché allora la conclusione di (2) è vera; oppure prendere i = 0 se T ( e , f ( 0 ) ) vale, perché allora ¬ T ( e , f ( 0 )i=f(0)T(e,f(0))i=0T(e,f(0)) non regge e la premessa di (2) è falsa, rendendola nuovamente vera.¬T(e,f(0))

Quindi, il modo di interpretare computazionalmente un teorema classico come (1) è guardare a una formulazione (classicamente) equivalente che può essere dimostrata in modo costruttivo, nel nostro caso (2).

Le diverse interpretazioni sopra menzionate differiscono solo nel modo in cui viene visualizzata la funzione . Nel caso della realizzabilità e dell'interpretazione dialettica, ciò è esplicitamente dato dall'interpretazione, quando combinata con una qualche forma di traduzione negativa (come quella di Goedel-Gentzen). Nel caso di estensioni Curry-Howard con operatori chiamata-cc e continuazione della funzione f deriva dal fatto che il programma è autorizzato a "sapere" come un certo valore (nel nostro caso i verrà utilizzato), quindi f è la continuazione del programma intorno al punto in cui i è calcolata.ffifi

Un altro punto importante è che vuoi che il passaggio da (1) a (2) sia "modulare", cioè se (1) è usato per provare (1 '), allora la sua interpretazione (2) dovrebbe essere usata in modo simile per dimostrare l'interpretazione di (1 '), dire (2'). Tutte le interpretazioni sopra menzionate lo fanno, inclusa la traduzione negativa di Goedel-Gentzen.


8
Benvenuto! È bello vedere qui un teorico della prova esperta.
Neel Krishnaswami,

1
Grazie Paulo, la tua risposta ha chiarito una parte dell'immagine in un problema correlato su cui sto lavorando.
Kaveh,

17

È abbastanza noto che l'aritmetica classica e intuizionista sono equi e coerenti.

ϕ

G()=¬¬G(ϕψ)=¬¬(G(ϕ)G(ψ))G()=¬G(¬ϕ)=¬G(ϕ)G(ϕψ)=¬(¬G(ϕ)¬G(ψ))G(x.ϕ)=x.¬¬G(ϕ)G(x.ϕ)=¬x.¬(G(ϕ))G(P)=¬¬P

G(ϕ)

G(ϕ)ϕ

,,,¬

A,B::=x.A(x)|AB|AB|¬A|¬¬P

AG(A)A

Quindi, come dovresti pensarci in modo intuitivo?

  • ¬¬¬P=¬P

Ora, grazie a Curry-Howard, sappiamo come interpretare le prove nella logica intuizionistica come programmi funzionali. Quindi, una possibile risposta (ma non l'unica) alla domanda "qual è il contenuto costruttivo di una dimostrazione classica?" è il seguente:

Il contenuto computazionale di una prova classica è qualunque sia il contenuto computazionale della traduzione della sua prova (secondo la traduzione negativa).

G(A¬A)=¬(¬G(A)¬¬G(A))¬P¬¬P

¬A==A((G(A))((G(A))))

type bot = Void of bot
type 'a not = 'a -> bot

let excluded_middle : ('a not * 'a not not) not = fun (u, k) -> k u 

Cioè, se ottieni non-A e non-non-A, puoi semplicemente passare la prima negazione alla seconda per derivare la contraddizione che desideri.

Ora, che cos'è una continuazione trasformazioni di stile di passaggio?

  • ττ
  • 3+5C[3+5]3+5
  • τταα
  • eτ(τα)αe
  • Ma dobbiamo farlo in modo ereditario, in modo che ogni sotterfugio del programma abbia reso esplicita la sua continuazione.

Adesso,

  • ϕ¬¬ϕ
  • Tuttavia, mentre la nostra traduzione usa la negazione, non elimina mai realmente la falsa proposizione, quindi la traduzione funziona parametricamente in quella proposizione.
  • α
  • ϕ(ϕα)α
  • Questa è una trasformazione CPS.

Ho visto una "trasformazione" in CPS, poiché come ho già detto in precedenza, ci sono molte traduzioni negative che ti consentono di dimostrare questo teorema, e ognuna corrisponde a una diversa trasformazione CPS. In termini operativi, ogni trasformazione corrisponde a un diverso ordine di valutazione . Quindi non esiste un'interpretazione computazionale unica della logica classica, dal momento che hai delle scelte da fare e le differenze scelte hanno caratteristiche operative molto diverse.


3
Questa è un'ottima risposta Mi ha ricordato il documento di Wadler "Call-by-value è doppio al call-by-name": homepages.inf.ed.ac.uk/wadler/topics/call-by-need.html , che include un aneddoto davvero memorabile nella sezione 4 per spiegare la relazione tra callCC e il centro escluso.
sclv,

8

Ci sono intere conferenze sull'argomento delle prove non costruttive come programmi e io non sono un esperto in materia. Sopra, Neel Krishnaswami ha accennato a una risposta più lunga che sta preparando, che, a giudicare dal suo lavoro qui, sarà eccellente. Questo è solo un assaggio di una risposta.

P,P¬P

Set Implicit Arguments.

Axiom callcc : forall (A B : Set), ((A -> B) -> A) -> A.

Lemma lem : forall (A B:Set), sum A (A -> B).
Proof.
  intros.
  eapply callcc.
  intros H.
  right.
  intros.
  apply H.
  left.
  assumption.
Defined.

Recursive Extraction lem.

dà il codice O'Caml:

type ('a, 'b) sum =
  | Inl of 'a
  | Inr of 'b

(** val callcc : (('a1 -> 'a2) -> 'a1) -> 'a1 **)

let callcc =
  failwith "AXIOM TO BE REALIZED"

(** val lem : ('a1, 'a1 -> no) sum **)

let lem =
    callcc (fun h -> Inr (fun h0 -> h (Inl h0)))

La più chiara introduzione a ciò che ho visto è nella "Nozione di controllo di formule come tipi di controllo" di Tim Griffin .


3
Dovresti provare a estrarre in Scheme e dire che la procedura di estrazione dovrebbe estrarre il tuo callccda Scheme callcc. Quindi puoi davvero provare le cose.
Andrej Bauer,
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.