• Non ci sono risultati.

Appendice C : inferW stile funzionale (Realizzato da M.Bellia)

N/A
N/A
Protected

Academic year: 2021

Condividi "Appendice C : inferW stile funzionale (Realizzato da M.Bellia)"

Copied!
5
0
0

Testo completo

(1)

Appendice C : inferW stile funzionale

(Realizzato da M.Bellia)

/**

*** Algoritmo W di Hindely-Milner [...] adattato a Sigma_x ed espresso nel *** linguaggio funzionale tipo OCAML utilizato in Benjamin Pierce [...] ***

*** To formally introduce the algorithm we give first the structures of the main *** ingredients of the type checker: (a) the abstract syntax of the language

*** terms, (b) atomic types, type constructors and type schemes, (c) environments *** for typing term identifiers, and (d) the substitutions for refining type

*** schemes. ***

*** (a) Abstract syntax. The language terms are constructed according to the *** following algebraic data type definition (Hakell-Caml like):

***

*** data Term = Bool Information Bool_value *** | String Information String_value

*** | ... and so on for the other language primitive values

*** | Var Information Var_name

*** | Update Information Term Sel_name Term *** | Select Information Term Sel_name Actuals *** | Object Information Type_name SelMetPairs *** | Abstract Information Term Term Actuals

*** | Extract Information Term Term Sel_name Actuals *** | Method Information Formals Term

*** | Obj Information SelMetPairs ***

*** with the type expressions below *** type Actuals = [Term]

*** type SelMetPairs = [D(Sel_name,Term)] *** type Formals = [P(Var_name,TypeA)]

*** where Sel_name, Var_name, Type_name are OCAML types for identifiers of selections, *** variables and parameters, and object types, respectively.

***

*** (b) Atomic types and type constructors are defined by the data type TypeA below: ***

*** data TypeA = Void

*** | TyBool

*** | TyString

*** | ... and so on for the other atomic types

*** | TyObject [(Sel_name,Type)]

*** | TyArrow [Type] Type

***

*** The Atomic types include the unknown void.

*** The use of Type scheme extends (and replaces) the definition above with the *** type variables and the overdefined Top as it follows:

***

(2)

*** | ... and so on for the other atomic types

*** | TyObject [O(Sel_name,Type)]

*** | TyArrow [Type] Type

*** | Ty Type_var

*** | Top

***

*** (c) Environments are bindings from language identifiers to type schemes. *** As far as the type checking of the program proceeds, the type scheme, *** associated to each identifier, is refined by instantiating the variables *** occurring in it, to the inferred type.

***

*** type Environment = [(Identifier,TypeB)] ***

*** (d) Substitutions are bindings from type variables to type schemes. They make *** identical two (or more) distinct type schemes. Hence, substitutions are *** introduced according to the following definition:

***

*** type Substitution = [(Type_var,TypeB)] ***

*** **/

inferW:: Environment x Term --> Substitution x Type inferW ctx t = match t with (1) Bool(fi,v) --> ([], TyBool) | String(fi,s) --> ([], TyString) ... (2) | Var(fi,i) --> ([], getTypeFromCxt fi ctx i) | Update(fi,a,l,m) -->

let (Sa,Ta) = inferW cxt a in (3) let (Sm,Tm) = inferW Sa(cxt) m in (4) if (isTyArrow Tm)

then let A = Class Tm in

(5) if (A == Sm(Ta)) and (isTyObject A) then let Tm' = getTypeFromObj fi A l in

if (Tm == Tm') then (Sa.Sm, A) // just same type (6) else error fi "error selection clashes"

else error fi "update in non object term" else error fi "update with no method"

| Select(fi,a,l,pl) -->

let (Sa,Ta) = inferW cxt a in if (isTyObject Ta)

then let Tm = getTypeFromObj fi Ta l in // method type (7) let(Spl,Tpl) = unzip (map (\p.inferW Sa(cxt) p) pl) in // propagation on "pl" of the constraints on "a". let Sn = fold (\sub s. (sub.s)) Sa Spl // substitutions composition (8) let newX = newTypeVar() in // unconstrained new variable let T' = TyArr(Ta:Tpl,newX) in // for the method range,

(3)

(9) let Sf = Sn.mgu(Tm,Sn(T')) in // collect constraints on parameters

(Sf, Sf(newX))

else error fi "selection in non object term" | Object(fi,A,ls) -->

let parTypes = \(l m).(match m with

Method(fi,fl,by) --> (l,(normalize fi fl))

| _ --> top // ready for other extentions let (lY,list) = unzip (map partypes ls) in

let S = fold (\r ts. r.mgu(A,(Class ts)) [] list // unicity of the self type. if (S = top) then error fi "type mismatch in class self"

else

let objT = zip lY S(list) in let lstype = TyObject(objT) in let ctx' = addBinding cxt A lstype in

let cxt" = fold (\cxt O(l,ltype).addBinding cxt l ltype) cxt' objT in

let byType = // context is extended to complete analysis

\sub D(l,E(fi,fl,by)).

let Ts = getTypeFromCxt fi ctx" l in

let (Mpl,Tpl) = unzip fl in

let fl* = zip Mpl (Dom Ts) in

let cxt* = fold (\cxt P(x,type).addBinding cxt x type) sub(cxt") fl* in

let (S,T) = inferW cxt* by in

sub.S.mgu((Range Ts),T) in // substitutions composition let Sf = fold byType S ls in

(Sf,Sf(lstype)) | Abstract(fi,a,m,pl) -->

let (Sb,Tr) = inferW cxt m in let (Sa,Ta) = inferW cxt Sb(a) in

let (Sub,bool) = lessThan(Sb.Sa(cxt),Ta,Sa(Class tr))

// it uses subtype relation in checking types that satisfy the structure if (not bool) then error fi "method cannot apply in abstraction" else

let (Spl,Tpl) = unzip (map (\p.inferW Sb.Sa(cxt) p) pl) // propaga vincoli sul tipo di "a" ai tipi di "pl".

let Sn = fold (\sub s. (sub.s)) Sb.Sa Spl // substitutions composition let newX = newTypeVar() in

let T' = TyArr(Ta:Tpl,newX) in // new variable for inferring the range type let Sf = mgu(Sn(Tr),T') in // it collects constraints on parameters (Sf,Sf(newX))

| Extract(fi,a,o,l,pl) -->

let (So,To) = inferW cxt o in let (Sa,Ta) = inferW So(cxt) a in

if (not(isTypeObject To)) or (not(isTypeObject Ta)) then error fi "non object in selection"

else

let (Sub,bool) = lessThan(So.Sa(cxt),Ta,Sa(To)) in // subsumption if (not bool) then error fi "method cannot apply in abstraction" else let Tr = getTypeFromObj fi To l in // method type let (Spl,Tpl) = unzip (map (\p.inferW Sb.Sa(cxt) p) pl)

(4)

let newX = newTypeVar() in let T' = TyArr(Sa(To):Tpl,newX) in

let Sf = mgu(Sn(Tr),T') in // it collects constraints on types (Sf,Sf(newX))

| method(fi,fl,by) -->

let (Tv->A) = normalize fl in // complete signature of the method let parList = zip tv ((2.unzip) fl) // list of (name,type)_parameters. // 2 select second component in pairs

let cxt* = fold (\cxt P(x,type).addBinding cxt x type) cxt parList in let (Sb,T) = inferW cxt* by in

let S = Sb.mgu(A,T) in

// usefull with polymorhic types: A may be also a non variable type (S,S(Tv->A))

| Object(fi,ls) -->

let A = newIdeType in inferW cxt Object(fi,A,ls) | _ ? error fi "term expected"

Note:

(1) [ ]: utilizzato, secondo i casi, come lista vuota o sostituzione identità. (2) getTypeFromObj:: Information x TyObject x Sel_name --> TypeB Ad esempio, (getTypeFromObj fi A l) è il tipo del metodo associato ad l in A, if any. In caso contrario, vale top (segnala error fi "selection not found"). Similmente,

getTypeFromCxt:: Information x Environment x Identifier --> TypeB addBinding:: Environment Identifier TypeB --> Environment

(3) Sa(cxt), Sn(pl): applicazione della sostituzione Sa a tutti i tipi (schemi di tipo) legati agli identificatori tipati in cxt. Similmente per una lista pl. p.q: composizione di sostituzioni nel modo usuale.

Tm==tm': impone che valore (i.e. metodo) associato ad un selettore di un oggetto mantenga il tipo attribuito al selettore quando l'oggetto è stato definito (introdotto). (4) isTyObject A: predicato vero se A è un tipo object_type.

isTyArrow m: predicato vero se m è un tipo metodo. Range TyArr(pl,T) = T tipo del rango

Dom TyArr(pl,T) = pl lista tipi

Class TyArr((P(x,A)|L),T) = A tipo del self del metodo.

(5) sui tipi è definita una relazione == come usuale uguaglianza strutturale con caso particolare: (top == top) è false.

(6) error:: Information x MessageString --> TypeB It throws an exception and return type Top.

(5)

: :: a x [a] --> [a] usuale cons. ++ :: [a] x [a] --> [a] usuale append

fold:: (a -> b -> a) -> a -> [b] -> a è il left-folding: fold f r [] = r

fold f r [x:xs] = fold f (f r x) xs map:: (a -> b) -> [a] -> [b] la solita map unzip:: [(a,b)] -> ([a],[b]) la solita unzip

(8) newTypeVar(): introduce una nuova variabile di tipo, ovvero Ty Type_var. (9) mgu: most general unifier

normalize: Information -> [(Var-name,TypeA)] -> TypeB

normalizza segnature nelle quali parte (o la totalit ) dei formali non hanno tipo esplicito.

Un'implementazione è la seguente: normalize fi fl =

let tv = normalizeArg fi fl in

let newX = newTypeVar in // una variabile di tipo per il range TyArr(tv,newX) // tipo dell'astratto

where normalizeArg fi FL =

match fl with

[(_,Void):Rt] --> let t = newTypeVar in // variabile di tipo let Lt = normalizeArg Rt in

t:Lt

| [(_,type):Rt] --> let t = type // tipo

let Lt = normalizeArg Rt in

t:Lt | [] --> []

Riferimenti

Documenti correlati

[r]

in seta, satin, fibre sintetiche o miste (ad es. tende)ispeedPerfect,¢ecoPerfect,Ô (Antipiega),hü(Risciacquo Extra), c(Stop risciacquo);nessuna centrifuga tra un risciacquo e l'altro ÿ

stiamo tutti affrontando un periodo senza precedenti, caratterizzato da una generale mancanza di materie prime e da aumenti improvvisi, ripetuti e consistenti di tutte le

Gianfranco Comaschi è stato chiamato alla vicepresidenza proprio in relazione al ruolo di supervisione delle attività di con- servazione e di valorizzazione della cultura

'PIETRO

POS POS MW POS CAT BIB COGNOME NOME SEX CAT SOC NAZ TIME REAL TIME.. 1 1 1 3408 ZANCAN STEFANO M

La radiolina ci può dare anche un'idea della stabilità, dato che le broadcastings devono trasmettere esattamente sulla loro frequenza. Ammettiamo di avere una

punto avrete sotto i vostri oc­ In ogni caso il trimmer MAX chi la scheda del modulo POS permette di ridurre la CNTL UNIT, sulla quale do­ massima potenza di uscita a vrete