• Non ci sono risultati.

Linguaggi di Programmazione avanzati Linguaggi funzionali

N/A
N/A
Protected

Academic year: 2021

Condividi "Linguaggi di Programmazione avanzati Linguaggi funzionali"

Copied!
28
0
0

Testo completo

(1)

Linguaggi di Programmazione avanzati Linguaggi funzionali

Simone Martini

Dipartimento di Scienze dell’Informazione Universit`a di Bologna

Italy

A.a. 2005-2006

(2)

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

(3)

Monadi: effetti collaterali in ambiente puro

I

In linguaggi call-by-value gli effetti collaterali sono aggiunti, ottenendo linguaggi impuri

I

Nei linguaggi puri, il flusso dei dati ` e totalmente esplicito

I

Talvolta questo ` e molto pesante, quando non impossibile

I

Discuteremo un esempio (P. Wadler, 1995)

(4)

Valutatore di espressioni

I

Sintassi Haskell-like

I

Il tipo dei termini

d a t a T e r m = Con Int | Div T e r m T e r m ; I

La funzione di valutazione

e v a l :: T e r m - > Int e v a l ( Con n ) = n

e v a l ( Div t u ) = ( e v a l t ) / ( e v a l u ) I

Due termini

ok = Div ( Div ( Con 2 0 0 0 ) ( Con 2)) ( Con 5) ko = Div ( Con 2 0 0 0 ) ( Con 0)

I e v a l ok = 200 e v a l ko indefinito

(5)

Eccezioni

I

Per sollevare eccezioni dobbiamo estendere il tipo dei valori:

eval pu` o restituire un Int oppure un’eccezione

I type M a = Excp | Value a

I ExcpeValuesonocostruttori

I M a `e un tipo polimorfo. Per ogni tipo T abbiamo il tipo M T

I A noi interessa M Int, i cui valori sono:

I Excp

I Value n

I

Il nuovo tipo di eval

eval :: Term -> M Int

(6)

Valutatore con eccezioni

I e v a l :: T e r m - > M Int e v a l ( Con a ) = V a l u e a e v a l ( Div t u ) =

c a s e e v a l t of E x c p - > E x c p

V a l u e a - > c a s e e v a l u of E x c p - > E x c p V a l u e b - > if b = 0

t h e n E x c p

e l s e V a l u e ( a / b )

I e v a l ok = V a l u e 200 e v a l ko = E x c p

I

Il risultato deve essere controllato ad ogni chiamata

(7)

Valutatore con I/O

I

Si vogliono stampare tutti i valori intermedi calcolati dal valutatore

I

Occorre estendere il tipo dei valori: eval restituisce sia un Int, sia l’output (una stringa, per esempio)

I d a t a M a = ( Output , a ) t y p e O u t p u t = S t r i n g I e v a l :: T e r m - > M Int

e v a l ( Con a ) = ( ’ Con ’ ++ ( s h o w I n t a ) , a ) e v a l ( Div t u ) =

let ( x , a ) = e v a l t in let ( y , b ) = e v a l u in

( x ++ y ++ ’ Div ’ ++ ( s h o w I n t a / b ) , a / b ) I showInt :: Int -> String

converte un intero in stringa

(8)

Valutatore con I/O, 2

I e v a l :: T e r m - > M Int

e v a l ( Con a ) = ( ’ Con ’ ++ ( s h o w I n t a ) , a ) e v a l ( Div t u ) =

let ( x , a ) = e v a l t in let ( y , b ) = e v a l u in

( x ++ y ++ ’ Div ’ ++ ( s h o w I n t a / b ) , a / b ) I ok = Div (Div (Con 2000) (Con 2)) (Con 5)

I eval ok = (x, 100)

dove

x

` e la stringa:

Con 2000 Con 2 Div 1000 Con 5 Div 200 I

Se volessimo ottenere la stampa a rovescio

Div 200 Con 5 Div 1000 Con 2 Con 2000

basterebbe usare il termine

’Div’ ++ (showInt a/b) ++ y ++ x

(9)

Valutatore con stato

I

Si vuole contare il numero di moltiplicazioni

I

Il tipo dei valori:

d a t a M a = S t a t e - > ( a , S t a t e ) t y p e S t a t e = Int

Un valore ` e una funzione che prende lo stato iniziale e restituisce il valore calcolato e accoppiato allo stato finale.

I e v a l :: T e r m - > M Int e v a l ( Con a ) x = ( a , x ) e v a l ( Div t u ) x =

let ( a , y ) = e v a l t x in let ( b , z ) = e v a l u y in

( a / b , z + 1)

(10)

Impariamo dagli esempi

I

Un tratto comune degli esempi Invece di:

eval :: Term -> Int

Abbiamo:

eval :: Term -> M Int

I

Intuitivamente:

eval

restituisce un

Int

, pi` u gli effetti aggiuntivi descritti dall’opportuno

M

.

I

Quali sono le operazioni che sono possibili sui valori di tipo

M a

?

I

Cerchiamo di capirlo guardando i nostri valutatori. . .

(11)

Operazioni sui tipi monadici, 1

I

Il valutatore con eccezioni:

e v a l :: T e r m - > M Int eval (Con a) = Value a e v a l ( Div t u ) =

c a s e e v a l t of E x c p - > E x c p

V a l u e a - > c a s e e v a l u of E x c p - > E x c p V a l u e b - > if b == 0

t h e n E x c p

e l s e V a l u e ( a / b ) I

Usiamo un modo “canonico” per trasformare un valore di tipo

Int

nel corrispondente valore di tipo

M Int

.

I

Chiamiamo

return :: a -> M a

questa “immersione”

return n = Value n

(12)

Operazioni sui tipi monadici, 2

I e v a l :: T e r m - > M Int e v a l ( Con a ) = V a l u e a e v a l ( Div t u ) =

c a s e e v a l t of E x c p - > E x c p Value a - > ...

V a l u e (a/ b )

I eval t

d` a il risultato

Value a

dal quale estraiamo il valore

a

per usarlo successivamente (nella divisione

a/b

)

I

Una funzione

g :: Int -> Int g = λ a . ... V a l u e ( a / b ) I eval t :: M Int

I

Dobbiamo applicare

g

al “risultato di

eval t

” (ma i tipi non

tornano esattamente)

(13)

Operazioni sui tipi monadici, 3

I

Ricapitolando:

g :: Int -> Int

,

eval t :: M Int I

In generale:

applicare una funzione di tipo

a -> M b

ad una computazione di tipo

M a

I

Abbiamo bisogno dunque di un’operazione

>>= :: M a -> (a -> M b) -> M b

che scriviamo infissa

t >>= g

Osserva che

t :: M a

mentre

g :: a -> M b I

Nel caso delle eccezioni:

t > >= g = c a s e t of

E x c p - > E x c p V a l u e a - > g a

(14)

Monadi

I

Una monade ` e una tripla

(M, return, >>=)

dove:

I M

` e un costruttore di tipo

I return :: a -> M a

I >>= :: M a -> (a -> M b) -> M b

I

Le due operazioni devono soddisfare tre leggi che vedremo tra

poco

(15)

Valutatore monadico

I

Data una monade M, possiamo scrivere il generico valutatore su di essa

I e v a l :: T e r m - > M Int e v a l ( Con a ) = r e t u r n a e v a l ( Div t u ) =

e v a l t > >= (λ a . e v a l u > >=

λ b . return ( a / b ))

(16)

Valutatore monadico per le eccezioni

I

Monade

I type M a = Excp | Value a

I return :: a -> M a return a = Value a

I >>= :: M a -> (a -> M b) -> M b t > >= g = c a s e t of

E x c p - > E x c p V a l u e a - > g a I

Valutatore

e v a l :: T e r m - > M Int e v a l ( Con a ) = r e t u r n a e v a l ( Div t u ) =

e v a l t > >= (λ a . e v a l u > >=

λ b . if b =0

t h e n E x c p

e l s e r e t u r n ( a / b ))

(17)

Monade dello I/O

I

Monade

I type M a = (Output, a)

I type Output = String

I return :: a -> M a return a = (’’,a)

I >>= :: M a -> (a -> M b) -> M b t > >= g = let ( x , a ) = t in

let ( y , b ) = g a in ( x ++ y , b )

I out :: Output -> M () out e = (x, ())

(18)

Valutatore monadico con I/O

I

Ricorda:

t > >= g = let ( x , a ) = t in

let ( y , b ) = g a in ( x ++ y , b ) out :: Output -> M ()

out e = (x, ()) I

Valutatore

e v a l :: T e r m - > M Int

e v a l ( Con a ) = out ( ’ Con ’ ++ ( s h o w I n t a ))

> >= λ(). r e t u r n a e v a l ( Div t u ) =

e v a l t > >= (λ a . e v a l u > >= λ b .

out ( ’ Div ’ + + ( s h o w I n t a / b )) > >=

λ(). return ( a / b )

(19)

Monade dello stato

I

Monade

I type M a = State -> (a, State)

I type State = Int

I return :: a -> M a r e t u r n a = λx .( a , x )

I >>= :: M a -> (a -> M b) -> M b

t > >= g = λx . let ( a , y ) = t x in

let ( b , z ) = g a y in ( b , z )

I tick :: M ()

t i c k = λx .(() , x +1)

(20)

Valutatore monadico con stato

I

Ricorda:

t > >= g = λx . let ( a , y ) = t x in

let ( b , z ) = g a y in ( b , z ) t i c k :: M ()

t i c k = λx .(() , x +1) I

Valutatore

e v a l :: T e r m - > M Int e v a l ( Con a ) = r e t u r n a e v a l ( Div t u ) =

e v a l t > >= (λ a . e v a l u > >= λ b .

t i c k > >= λ(). r e t u r n ( a / b )

(21)

Leggi

I

Neutro a sinistra

r e t u r n a > >= λb . n = n [ a / b ] I

Neutro a destra

m > >= λ a . r e t u r n a = m I

Associativit` a

m > >= λ a . ( n > >= λ b . o ) = ( m > >= λ a . n ) > >= λ b . o

Osserva che deve essere a 62 FV (o)

I

Esercizio: Verifica le leggi per le monadi introdotte

I

Le leggi servono per dimostrare propriet` a dei programmi

(22)

Monadi: una variante

I

Una monade pu` o essere definita anche come

(M, return, join, map)

con

map :: ( a - > b ) - > ( M a - > M b ) j o i n :: M ( M a ) - > M a

e le leggi

I map id = id

map ( f  g) = map f  map g map f  return = return  f

map f  join = join  map ( map f ) j o i n  return = id

j o i n  map return = id

j o i n  map join = join  join

(23)

Le due definizioni sono equivalenti

I

Definiamo

map

e

join

in termini di

>>=

map f m = m > >= λa . r e t u r n ( f a ) j o i n z = z > >= λm . m

I

Definiamo

>>=

in termini di

map

e

join m > >= k = j o i n ( map k m )

I

Esercizio: verificare le leggi in entrambi i casi.

(24)

La monade pi` u semplice: Identit` a

I

Monade

I type M a = a

I return :: a -> M a return a = a

I >>= :: M a -> (a -> M b) -> M b t >>= g = g t

I

Il generico valutatore monadico su questa monade concide col

valutatore “puro”

(25)

Liste come monadi

I

Vedere le liste come monadi pu` o essere utile

I

Monade

I type L a = [a]

Notazione Haskell: [Int] liste di interi

I return :: a -> L a return a = [a]

I >>= :: L a -> (a -> L b) -> L b l >>= g = concat (map g l) I

Esempio:

[10 ,20 ,30] > >= λx .[ x , x +1]

ha come risultato

[10,11,20,21,30,31]

(26)

Notazioni Haskell

I

Riprendiamo il valutatore con I/O

e v a l :: T e r m - > M Int

e v a l ( Con a ) = out ( ’ Con ’ ++ ( s h o w I n t a ))

> >= λ(). r e t u r n a e v a l ( Div t u ) =

e v a l t > >= (λ a . e v a l u > >= λ b .

out ( ’ Div ’ + + ( s h o w I n t a / b )) > >=

λ(). return (a/b) I

Alcune volte in

m >>= g

il valore di

m

non ` e usato

I

Notazione apposita:

>> :: M a -> M b -> M b

, definito come

m > > n = m > >= λ(). n I

Cos`ı risparmiamo qualche λ. . .

(27)

Notazione do

I

Il valutatore con I/O, ottimizzando i λ

e v a l ( Con a ) = out ( ’ Con ’ ++ ( s h o w I n t a )) >>

r e t u r n a e v a l ( Div t u ) =

e v a l t > >= (λ a . e v a l u > >= λ b .

out ( ’ Div ’ + + ( s h o w I n t a / b )) >>

r e t u r n ( a / b ) I

Osserva:

>>

` e come

;

in C

>>=

` e simile ad un assegnamento.

I

La notazione

do

:

e v a l ( Con a ) = do out ( ’ Con ’ ++ ( s h o w I n t a )) r e t u r n a

e v a l ( Div t u ) = do a < - e v a l t b < - e v a l u

out ( ’ Div ’ + + ( s h o w I n t a / b )) r e t u r n ( a / b )

(28)

Notazione do, 2

I

Il valutatore con stato

e v a l ( Con a ) = r e t u r n a e v a l ( Div t u ) =

e v a l t > >= (λ a . e v a l u > >= λ b .

t i c k >> return (a/b) I

Diviene:

e v a l ( Con a ) = do r e t u r n a e v a l ( Div t u ) = do a < - e v a l t

b < - e v a l u t i c k

r e t u r n ( a / b )

Riferimenti

Documenti correlati

Il programmatore puo` astrarre dai dettagli legati all’architettura ed esprimere i propri algoritmi in modo simbolico. ☞ Sono indipendenti dalla

Siccome le regole specificano il significato delle espressioni in modo operazionale, si dice che esse definiscono una semantica operazionale di tali espressioni. Alcune regole

Induzione matematica e strutturale sono casi particolari di un potente metodo di prova chiamato induzione ben fondata In questa lezione vedremo in dettaglio:. ¾ Induzione

Supponiamo di voler estendere le espressioni aritmetiche di IMP includendo un nuovo operatore “^” con il significato di elevamento a potenza. La sintassi di Aexp di IMP verrà

Negli anni sessanta, Christopher Strachey e Dana Scott riuscirono a superare le limitazioni della semantica operazionale introducendo una semantica più astratta basata sull’utilizzo

La sintassi specifica sia la struttura lessicale del linguaggio (come costruire le parole a partire dai caratteri dell’alfabeto) sia le regole per la costruzione delle

Si noti che nel comando if, comunque sia valutato b in σ’, esso viene interrotto dopo l’esecuzione di c e dunque in questo caso &lt;w,σ&gt; è valutato σ’ sse &lt;if,σ&gt;.

Passo induttivo: supponendo che l’asserto sia vero per un albero di derivazione alto n e per n cicli di valutazioni nella denotazione del while (con n &gt; 0, quindi anche per