70 likes | 363 Views
Paradigma Imperativo: Programma = transizione di stato Paradigma Funzionale: Programma = valutazione di un’espressione La maggior parte dei linguaggi imperativi ha costrutti applicativi. Paradigma Funzionale. Esempio: consideriamo la seguente grammatica LF. Prog ::= Decs eval Exp.
E N D
Paradigma Imperativo: Programma = transizione di stato Paradigma Funzionale: Programma = valutazione di un’espressione La maggior parte dei linguaggi imperativi ha costrutti applicativi. Paradigma Funzionale Esempio: consideriamo la seguente grammatica LF Prog ::= Decs eval Exp. Decs ::= Dec | Dec Decs. Dec ::= CDec | FDec. CDec ::= Type Id = Exp;. FDec ::= Type Id(PDecs) {Exp}. PDecs ::= PDec | PDec PDecs. PDec ::= Type Id; Type ::= int | bool | Types Type Types ::= Type | Type Types Exp ::= Id | Id(Exps) | Exp + Exp | … if (Exp) {Exp} else {Exp}. Exps ::= Exp | Exp, Exps.
Confronto con LW I costrutti di LF sono in gran parte simili a quelli di LW. Rispetto a LW, una (grossa) differenza è che oltre ai tipi base, compaiono dei tipi funzionali o higher-order. Quindi LF è un linguaggio per manipolare valori che possono essere base ([int] = Z, [bool] = B) o funzionali (definiti induttivamente da [t1 ... tn t] = [[t1] ... [tn] P[t]]). Nel seguito useremo Value = tLType(LF) [t]. I tipi higher-order sono cittadini di prima classe, cioè possono comparire in tutti i contesti in cui può comparire un tipo base (eg come argomenti e risultati di funzioni). Principale differenza con linguaggi funzionali “reali”: manca il polimorfismo e i tipi sono dichiarati invece che dedotti. La semantica di LF sarà molto simile a quella di LW, ma, non essendo necessaria la nozione di stato, tutto si semplificherà.
types(pl)= tl types(t x; pl)= t tl [dl]sD([],[]) = r [e]sE (r) = t [dl eval e]sP = t [d]sD(rg, rl) = rl’ [dl]sD(rg, rl’) = r types(t x;)= t [d dl]sD (rg, rl)= r [e]sE(rg[rl]) = t xÏDom(rl) xÏDom(rl) [t x = e;]sD (rg, rl)= rl[t/x] [t x;]sPD (rg, rl)= rl[t/x] [pl]sPD(rg[rl],[lt t/f]) = rl’ [e]sE(rg[rl][rl’]) = t fÏDom(rl) lt = types(pl) [t f(pl){e}]sD (rg, rl)= rl[lt t/f] Semantica Statica Ignoriamo il trattamento di errore (cioè definiamo la semantica statica come funzione parziale) Envs = [LId(LF) PLType(LF) ]Fin [_]sD:LDecs(LF) Envs EnvsPEnvs [_]sE:LExps(LF) EnvsPLType(LF)+ [_]sP:LProg(LF) PLType(LF) [_]sPD:LPDecs(LF) Envs EnvsPEnvs
r(x) = t [x]sE (r) = t [f]sE (r) = lt t [es]sE (r) = lt [f(es)]sD (r)= t [e]sE(r) = int [e’]sE(r) = int [b]sE(r) = bool [e + e’]sE(r)= int [e]sE(r) = t [e’]sE(r) = t [if (b) {e} else {e’}]sE(r)= t Semantica Statica 2 Esercizio proposto: aggiungere altri costrutti base al linguaggio, ad esempio costrutti per la funzione identica, composizione di funzioni, tipi prodotto, pairing (se f: A B e g: C D, allora (f,g): A C B D è definita da (f,g)(a,c) = (f(a),g(b)))...
[e]E(r) = v [t x = e;]D (r)= r[v/x] [e](r[/f, v/x])= a F(v) = a [dl]D([]) = r [e]E (r) = v Rispetto a LW è sparito lo stato [dl eval e]P = v [RT f(T x) {e}]D(r) = r[F/f] Il valore del parametro attuale è associato direttamente al nome del parametro formale [d]D(r) = r’ [dl]D(r’) = r” [d dl]D (r)= r” [e](r[/f]) = v F(v) = a [f(e)](r[/f]) = a Semantica Dinamica (Denotazionale) Le dichiarazioni modificano l’ambiente: [_]Decs:LDecs(LF) Env Env dove Env = [LId(LF) PValue]Fin Le espressioni producono un valore: [_]Exps:L Exps(LF) Env Value+ Dove F : [T] [RT] è definita induttivamente da tutte le regole della semantica più le seguenti due: Caso base Regola ad hoc per la chiamata di f
[e]E(r) = v [es]E(r) = lv [e es]E(r) = v lv [x]E(r) = r(x) [e1]E(r) = v1 [e2]E(r) = v2 [e1 + e2]E(r) = a [es]E(r) = lv [f(es)]E(r) = r(f)(lv) Semantica Dinamica (2) v1 + v2 = a