LAMBDA CALCOLO
Nasce contemporaneamente alla macchina di Turing con l’obbiettivo di descrivere ogni algoritmo (Turing-equivalente), e basato sul solo concetto di funzione
SINTASSI E SEMANTICA
dove può esprimere qualunque struttura dati e qualunque algoritmo
invece rappresenta una trasformazione atomica che applica la sostituzione di testo, ovvero nella espressione
La semantica risulta essere sostituisci tutte le occorrenze del parametro nel corpo della funzione con risultato , l’operazione e detta riduzione
Notare che la grammatica cosi definita e ambigua e derivazioni diverse di una stessa frase portano a semantiche diverse, per esempio la frase
può essere interpretata come:
applicare il parametro alla funzione di corpo e parametro formale
oppure:
funzione di parametro e corpo
LAMBDA CALCOLO IN JAVASCRIPT
javascript risulta essere pratico per l’implementazione del lambda calcolo in quanto vi e la possibilità di definire funzioni anonime e chiusure
//il termine lambda x.<expr> puo infatti essere definito come
f = function (x){return x;}//per semplicita eseguiamo la funzione identita
//mentre la chiamata puo essere interpretata come una chiamata di funzione stessa
y=5
console.log(f(y))
FUNZIONI A PIÙ ARGOMENTI
Funzioni a piu argomenti possono essere rappresentate come funzioni di funzioni sfruttando il currying, di conseguenza una funzione a piu argomenti:
Viene interpretata come una funzione di parametro e corpo una funzione di parametro e corpo
FUNZIONI NOTEVOLI
Esistono alcune funzioni notevoli cosi definite:
l'operatore riproduce sempre se stesso
FORMA NORMALE
Un lambda termine e in forma normale se non si possono applicare riduzioni ulteriori, ma dato che la grammatica e ambigua questa proprieta dipende dall’ordine di riduzione
- lambda termine fortemente normalizzabile se qualunque ordine di riduzione porta a una forma normale
f= function(x,y){ return x+y+1; }
console.log(f(2,4))
- lambda termine debolmente normalizzabile se almeno un ordine di riduzione porta a una forma normale
f=function(x){ return x==0 ? 0 : f(x); }
console.log(f(0))
qui funziona perche il parametro attuale e
- lambda termine non normalizzabile se nessun ordine di riduzione porta a una forma normale
f=function(x){ return f(x); }
f(2)
esplode lo stack, ovviamente
TEOREMA DI CHURCH-ROSSER
Ogni lambda termine ha al piu una forma normale
Da questo si deriva che il lambda calcolo e deterministico, i grafi hanno una e una sola foglia (se sono aciclici)
LOGICA BOOLEANA CON IL LAMBDA CALCOLO
Per rappresentare la logica booleana sono necessari:
- due valori distinti per
TRUE
eFALSE
- le operazioni
AND
OR
NOT
Che in lambda calcolo divengono:
- T=
- F=
- NOT=
- AND=
- OR=
che in javascript diventa:
//uso pesante del curring come discusso prima
t = function(x) { return function(y) { return x; }}
f = function(x) { return function(y) { return y; }}
n = function(x) { return x(f)(t) }
a = function(x) { return function(y){ return x(y)(f); }}
o = function(x) { return function(y){ return x(t)(y); }}
console.log(n(t))
console.log(n(f))
console.log(a(t)(f))
console.log(o(t)(f))
notare che i simboli
T
eF
sono esistessi definiti come termini funzione, anche se riducibili, a testimonianza del fatto che il lambda calcolo e capace di rappresentare qualunque struttura dati e algoritmo con un solo formalismo sintattico :)
STRATEGIE DI RIDUZIONE
Come mostrato prima la procedura di riduzione non e detto porti sempre a una forma normale, e pertanto importante determinare la strategia con cui si decide di ridurre la frase:
STRATEGIE EAGER
Basate sul concetto di sviluppare il prima possibile i termini sulla destra
- Applicative order (rightmost innermost)
- Call by value
- Call by reference
- Call by copy-restore
STRATEGIE LAZY
Basate sul applicazione dell’argomento alla funzione piuttosto che alla risoluzione dell’argomento stesso
- Normal order (leftmost outermost)
- Call by name
- Call by need
- Call by macro
TURING EQUIVALENZA
Il lambda calcolo e Turing equivalente, ovvero e in grado di rappresentare
- i numeri naturali
- il concetto di successore
- il concetto di proiezione
- il concetto di composizione
- la ricorsione
RICORSIONE NEL LAMBDA CALCOLO
Per poter rappresentare la ricorsione e necessario poter richiamare le funzioni per nome, tuttavia nel lambda calcolo le funzioni sono anonime ergo questo non e possibile.
Si introduce quindi il concetto di operatore di punto fisso che e cosi definito
Che applicato a una funzione ha l’effetto di ‘rigenerarla’
Si dice infatti che e un punto fisso per la funzione
l'operatore di punto fisso e possibile solo se si adotta come strategia di riduzione la call by name in quanto le altre strategie divergerebbero
function Y(f) {
return (
//con la call by value si cerca di valutare x all'infinito
(function(x) {return f( x(x) ); })
(function(x) {return f( x(x) ); })
);
}
E necessario simulare la call by name come già visto
COMBINATORE DI PUNTO FISSO RIVISITATO
Per poter operare con la call by value e necessario ridefinire l’operatore di punto fisso come segue
Che in javascript si traduce
function Z(f) {
return (
(function (x) {
return f( function(v){ return x(x)(v); } ); })
(function (x) {
return f( function(v){ return x(x)(v); } ); })
);
}
IMPLEMENTAZIONE DELLA RICORSIONE
Dato l’operatore di punto fisso per ricreare la ricorsione e necessario:
-
definire una funzione di ordine superiore che abbia come punto fisso la funzione che si desidera rendere ricorsiva
-
separare la business logic della funzione ricorsiva in un altra funzione
-
lasciar gestire al combinatore di punto fisso la ricorsione
Di seguito un esempio con il calcolo del fattoriale
// Z utilizzato per gestire la call by value
function Z(f) {
return (
(function (x) {
return f( function(v){ return x(x)(v); } ); })
(function (x) {
return f( function(v){ return x(x)(v); } ); })
);
}
//funzione di ordine superiore con la business logic come punto fisso
FactGen = f => x => (x==0) ? 1: x*f(x-1)
console.log(Z(FactGen)(3))
IN CONCLUSIONE
Il lambda calcolo e un formalismo estremamente potente che ha permesso di formalizzare le funzionalità che oggi vantano i linguaggi mainstream ma non e pensato per essere utilizzato direttamente dagli utenti finali