Derivazione chiara e intuitiva del combinatore a punto fisso (combinatore a Y)?


28

Il combinatore a virgola fissa FIX (noto anche come il combinatore Y) nel calcolo lambda (non tipizzato) ( λ ) è definito come:

FIX λf.(λx.f (λy.x x y)) (λx.f (λy.x x y))

Capisco il suo scopo e posso tracciare perfettamente l'esecuzione della sua applicazione; Vorrei capire come derivare FIX dai primi principi .

Ecco quanto ottengo quando provo a derivarlo da solo:

  1. FIX è una funzione: FIX λ
  2. FIX accetta un'altra funzione, f , per renderlo ricorsivo: FIX λf.
  3. Il primo argomento della funzione f è il "nome" della funzione, utilizzato dove è prevista un'applicazione ricorsiva. Pertanto, tutte le apparenze del primo argomento in f dovrebbero essere sostituite da una funzione e questa funzione dovrebbe aspettarsi il resto degli argomenti di f (supponiamo che f prenda un argomento): FIX λf.f (λy.y)

È qui che non so come "fare un passo" nel mio ragionamento. Le piccole ellissi indicano dove manca il mio FIX (anche se sono in grado di saperlo solo confrontandolo con il FIX "reale").

Ho già letto Tipi e linguaggi di programmazione , che non tenta di derivarlo direttamente, ma rimanda invece il lettore a The Little Schemer per una derivazione. Ho letto anche quello e la sua "derivazione" non è stata così utile. Inoltre, è meno una derivazione diretta e più un uso di un esempio molto specifico e un tentativo ad hoc di scrivere una funzione ricorsiva adatta in λ .


1
Questo post potrebbe essere utile. In generale, penso che solo analizzare e analizzare diverse iterazioni del combinatore sia utile per capire perché funziona.
Xodarap,

2
Esistono diversi combinatori di punti fissi. Forse le persone hanno solo giocato con i combinatori fino a quando non si sono imbattuti in loro.
Yuval Filmus,

@YuvalFilmus, questo è ciò che la mia ricerca e la risposta a questa domanda stanno iniziando a farmi pensare. Ma continuo a pensare che sarebbe istruttivo "vedere" come si formano i combinatori logicamente, un'abilità che sarebbe particolarmente utile quando, ad esempio, si cerca di costruire un nuovo combinatore.
BlueBomber

Leggi il capitolo 9 in "The Little Lisper", di Daniel P. Friedman (o "The Little Schemer").
user18199

2
L'OP sembra indicare che l'hanno già letto.
Raffaello

Risposte:


29

Non l'ho letto da nessuna parte, ma è così che credo che avrebbe potuto essere derivato:Y

Diamo una funzione ricorsiva , forse un fattoriale o qualcos'altro del genere. Informalmente, definiamo come termine pseudo-lambda in cui presenta nella sua stessa definizione:fff

f=ff

Innanzitutto, ci rendiamo conto che la chiamata ricorsiva può essere fattorizzata come parametro:

f=(λr.(rr))Mf

Ora potremmo definire se solo avessimo un modo per trasmetterlo come argomento a se stesso. Questo non è possibile, ovviamente, perché non abbiamo a portata di mano. Quello che abbiamo a portata di mano è . Poiché contiene tutto ciò di cui abbiamo bisogno per definire , possiamo provare a passare come argomento invece di e provare a ricostruire da esso successivamente all'interno. Il nostro primo tentativo è simile al seguente:ffMMfMff

f=(λr.(rr))M(λr.(rr))M

Tuttavia, questo non è completamente corretto. Prima, ottenuto sostituito dentro . Ma ora passiamo invece aDobbiamo risolvere in qualche modo tutti i luoghi in cui usiamo in modo che essi ricostruiscono da . In realtà, questo non è affatto difficile: ora che sappiamo che , ovunque usiamo lo sostituiamo semplicemente con .frMMrfMf=MMr(rr)

f=(λr.((rr)(rr)))M(λr.((rr)(rr)))M

Questa soluzione è buona, ma abbiamo dovuto modificare all'interno. Questo non è molto conveniente. Possiamo farlo in modo più elegante senza dover modificare introducendo un altro che invia a suo argomento applicato a se stesso: Esprimendo come otteniamoMMλMMλx.M(xx)

f=(λx.(λr.(rr))M(xx))(λx.(λr.(rr))M(xx))

In questo modo, quando viene sostituito con , viene sostituito con , che è per definizione uguale a . Questo ci dà una definizione non ricorsiva di , espressa come termine lambda valido!MxMMrff

Il passaggio a ora è facile. Possiamo prendere un termine lambda arbitrario invece di ed eseguire questa procedura su di esso. Quindi possiamo scomporre e definireYMM

Y=λm.(λx.m(xx))(λx.m(xx))

In effetti, riduce a come l'abbiamo definito.YMf


Nota: ho derivato come è definito in letteratura. Il Combinator che hai descritto è una variante di per call-by-value lingue, a volte chiamato anche . Vedi questo articolo di Wikipedia .YYZ


1
Il-ma-apparentemente ovvia manca l'intuizione che la risposta eccellente mi ha dato è che una funzione ricorsiva stesso ha bisogno come un argomento, in modo da iniziare con un presupposto che la funzione avrà la forma per un po ' . Quindi, mentre costruiamo , facciamo uso di quella affermazione che è definito come l'applicazione di qualcosa a se stesso internamente in , ad esempio, applicando a nella tua risposta, che è per definizione uguale a . Affascinante! f=X(X)XXfXxxf
BlueBomber,

11

Come ha sottolineato Yuval, non esiste un solo operatore a virgola fissa. Ce ne sono molti. In altre parole, l'equazione per il teorema a virgola fissa non ha una sola risposta. Quindi non puoi derivarne l'operatore.

È come chiedere come le persone derivano come soluzione per . Non lo fanno! L'equazione non ha una soluzione unica.(x,y)=(0,0)x=y


Nel caso in cui ciò che vuoi sapere è come è stato scoperto il primo teorema a virgola fissa. Permettetemi di dire che mi chiedevo anche come fossero venuti fuori i teoremi a virgola fissa / ricorsione quando li ho visti per la prima volta. Sembra così geniale. Soprattutto nella forma della teoria della calcolabilità. A differenza di ciò che dice Yuval, non è il caso che le persone abbiano giocato fino a quando non hanno trovato qualcosa. Ecco cosa ho trovato:

Per quanto ricordo, il teorema è originariamente dovuto a SC Kleene. Kleene inventò il teorema originale in virgola fissa recuperando la prova di incoerenza del calcolo lambda originale della Chiesa. Il calcolo lambda originale di Church soffriva di un paradosso di tipo Russel. Il calcolo lambda modificato ha evitato il problema. Kleene ha studiato la prova di incoerenza probabilmente per vedere come se il calcolo lambda modificato avrebbe sofferto di un problema simile e ha trasformato la prova di incoerenza in un teorema utile nel calcolo lambda modificato. Attraverso il suo lavoro sull'equivalenza del calcolo lambada con altri modelli di calcolo (macchine di Turing, funzioni ricorsive, ecc.) Lo trasferì ad altri modelli di calcolo.


Come derivare l'operatore che potresti chiedere? Ecco come lo tengo a mente. Il teorema del punto fisso riguarda la rimozione dell'autoreferenzialità.

Tutti conoscono il paradosso bugiardo:

Sono una tana.

O nella forma più linguistica:

Questa frase è falsa.

Ora la maggior parte delle persone pensa che il problema con questa frase sia nell'autoreferenzialità. Non è! L'autoreferenzialità può essere eliminata (il problema è con la verità, una lingua non può parlare della verità delle proprie frasi in generale, vedere l'indefinibilità di Tarski del teorema della verità ). Il modulo in cui viene rimosso l'autoreferenzialità è il seguente:

Se scrivi la seguente citazione due volte, la seconda volta tra virgolette, la frase risultante è falsa: "Se scrivi la seguente citazione due volte, la seconda volta tra virgolette, la frase risultante è falsa:"

Nessun auto-riferimento, abbiamo istruzioni su come costruire una frase e poi fare qualcosa con essa. E la frase che viene costruita è uguale alle istruzioni. Nota che in -calculus non abbiamo bisogno di virgolette perché non c'è distinzione tra dati e istruzioni.λ

Ora se analizziamo questo abbiamo dove è le istruzioni per costruire e fare qualcosa per esso.MMMxxx

Mx=f(xx)

Quindi è e abbiamoMλx.f(xx)

MM=(λx.f(xx))(λx.f(xx))

Questo è per un fisso . Se vuoi renderlo un operatore aggiungiamo semplicemente e otteniamo :fλfY

Y=λf.(MM)=λf.((λx.f(xx))(λx.f(xx)))

Quindi tengo a mente il paradosso senza autoreferenzialità e questo mi aiuta a capire di cosa parlaY


3

Quindi è necessario definire un combinatore a punto fisso

fix f = f (fix f)
      = f (f (fix f))
      = f (f (f ... ))

ma senza ricorsione esplicita. Cominciamo con il combinatore irriducibile più semplice

omega = (\x. x x) (\x. x x)
      = (\x. x x) (\x. x x)
      = ...

Il xprimo lambda è ripetutamente sostituito dal secondo lambda. La semplice conversione alfa rende questo processo più chiaro:

omega =  (\x. x x) (\x. x x)
      =α (\x. x x) (\y. y y)
      =β (\y. y y) (\y. y y)
      =α (\y. y y) (\z. z z)
      =β (\z. z z) (\z. z z)

Cioè la variabile nella prima lambda scompare sempre. Quindi se aggiungiamo un falla prima lambda

(\x. f (x x)) (\y. y y)

la fvolontà finirà

f ((\y. y y) (\y. y y))

Abbiamo le omegaspalle. Dovrebbe essere chiaro ora che se aggiungiamo un falla seconda lambda, allora fapparirà nella prima lambda e poi si riavvolge:

Y f = (\x. x x)     (\x. f (x x))
      (\x. f (x x)) (\x. f (x x)) -- the classical definition of Y

Da

(\x. s t) z = s ((\x. t) z), if `x' doesn't occur free in `s'

possiamo riscrivere l'espressione come

f ((\x. x x) (\x. f (x x))

che è giusto

f (Y f)

e abbiamo la nostra equazione Y f = f (Y f). Quindi il Ycombinatore è essenzialmente

  1. raddoppia il f
  2. fare il primo fbobbed
  3. ripetere

2

Potresti aver visto il classico esempio di equazione senza una forma normale:

(λx.xx)(λx.xx)(λx.xx)(λx.xx)

Un'equazione simile è suggerita da quella per la ricorsione generale:

(A)(λx.R(xx))(λx.R(xx)) R( (λx.R(xx))(λx.R(xx)) )R(R( (λx.R(xx))(λx.R(xx)) ))

(A) è un modo per scrivere equazioni ricorsive generali nel calcolo lambda (oltre la ricorsività primitiva). Quindi, come risolvi l'equazione ? Inserisci per nell'equazione sopra per ottenere:Yf=f(Yf)fR

Yf=(λx.f(xx))(λx.f(xx))
Y=λf.(λx.f(xx))(λx.f(xx))
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.