Linguaggi di Programmazione avanzati Linguaggi funzionali
Simone Martini
Dipartimento di Scienze dell’Informazione Universit` a di Bologna
Italy
A.a. 2005-2006
Outline
Il paradigma funzionale puro Un lambda-calcolo esteso Strategie di riduzione
Programmare in un linguaggio funzionale Zucchero sintattico
Tipi e polimorfismo Aspetti imperativi La macchina SECD Monadi
Le continuazioni e la continuation passing transformation Continuazioni
La CPS
Le continuazioni come oggetti manipolabili: call/cc
Ricorsione di coda
I Sia f una funzione il cui corpo contenga una chiamata a g
I La chiamata di g ` e una chiamata in coda (tail call) se f restituisce il valore restituito da g senza ulteriore computazione.
I f ` e ricorsiva in coda (tail recursive) se tutte le chiamate in f sono chiamate in coda.
I Le funzioni ricorsive in coda possono (al primo ordine) essere eseguite con un solo RdA
I La continuation passing transformation permette di
trasformare ogni funzione in una ricorsiva in coda.
Continuation passing style
I Usato come trasformazione intermedia per alcuni linguaggi funzionali
I Eliminazione delle ricorsione
I Semplice
I Espone situazioni che possono essere (pi` u) facilmente ottimizzate da un compilatore
I Elimina molte sottoespressioni annidate
Continuazioni
I Fissato un punto in un programma, la sua continuazione ` e una funzione che esprime la computazione che verr` a eseguita dal resto del programma
I Una funzione che restituisce un valore, lo restituisce (implicitamente) alla sua continuazione
I La CPS rende esplicita sia la continuazione, sia il passaggio di valori alle continuazioni
I fun foo x = x+1;
Se k ` e un nuovo parametro di foo , che “sta per” la continuazione:
fun foo’ x k = k(x+1);
I “Una funzione non ritorna, continua”
I “Le continuazioni sono goto con argomenti”
Continuazioni, 2
I Supponiamo di avere due funzioni f(x,y) e g(x,y) con le quali definiamo una nuova funzione
fun fie x y = g(f(2,x),y)
I Trasformiamo f e g in CPS; otterremo
fun f’ (x,y) k = ...;
fun g’ (x,y) k = ...;
I Come viene trasformato fie ?
I Innanzitutto avremo fun fie’ (x,y) c = ...
I c ` e la continuazione di fie’
I Dunque c ` e la continuazione che deve essere passata a g’
I Ma quale continuazione deve essere passata a f’ ?
Continuazioni, 3
I fun fie x y = g(f(2,x),y)
I fun fie’ (x,y) c = ... g’ (...) c ...
I Ma quale continuazione deve essere passata a f’ ?
I f passa il proprio valore al “contesto” nel quale avviene la chiamata:
λv . g (v , y )
o meglio, usando g’ :
λv .g ’ (v , y ) c I Dunque avremo
fun fie ’ ( x , y ) c = f ’ (2 , x ) (λv . g ’ ( v , y ) c )
Continuazioni, 4
I fun fie x y = g(f(2,x),y)
I fun fie ’ ( x , y ) c = f ’ (2 , x ) (λv . g ’ ( v , y ) c )
I La CPS “isola” le sottoespressioni e le “sequenzializza”
introducendo dei nomi locali ( v ) per esse.
I Queste informazioni sono usate dal compilatore per la generazione di codice efficiente
I La chiamata di f’ ` e in coda
Ricorsione e CPS
I fun f a c t 0 = 1
| f a c t ( S n ) = ( S n ) * ( f a c t n ) I Supponiamo (per ora) che * non sia in CPS
I Otteniamo
fun fact ’ 0 k = k 1
| fact ’ ( S n ) k = fact ’ n (λv . k (( S n ) * v ) ) I La funzione fact’ ` e tail recursive, la sua valutazione ` e
sequenzializzata e ai temporanei ` e stato assegnato un nome.
I Se anche * ` e in CPS:
fun fact ’ 0 k = k 1
| fact ’ ( S n ) k = fact ’ n (λv . * ’ ( S n ) v k )
Continuation passing transformation
I Linguaggio sorgente, call by-value:
M, N ::= c | x | (λx.M) | (MN)
I Per M termine e k continuazione, definiamo [[M]]k la traduzione CPS di M con continuazione k
I Un programma M ` e tradotto con [[M]](λx .x )
I I valori (c, x , λx .M) li passiamo semplicemente alla continuazione:
I
[[c]]k = k c
I
[[x ]]k = k x
I
[[λx .M]]k = k (λx .λh.[[M]]h)
I In un’applicazione usiamo le continuazioni per esprimere l’ordine di valutazione:
I