CS 541 Lecture -*- Outline -*- * Fundamentals of Denotational Semantics advert: the math that we use for denotations ADT view of objects manipulated in semantics use sets as an example awareness: use examples... ** abstract vs. concrete syntax concrete syntax is used to parse expressions e.g., page 7 at bottom is all that detail necessary? abstract syntax used to generate trees may not work for parsing e.g., page 10 conventions, section 1.1 give abstract syntax for the lambda calculus? ** structural induction (section 1.2) write append for lists, how do you prove it's correct how to prove properties of ML functions defined on datatypes in general? same idea for abstract syntax. ** Sets (see Schmidt: 2.1) what defines a set? how do we know when two sets are equal? *** operations constructors {...} { x | P(x)} these are *presentations* of sets, not sets observers (disassembly) in (epsilon) *** extensionality principle sets equal only if they have same members *** derived constructions on sets **** powerset: |P(R) = { x | x subsetOf R} **** product: R x S = { (x,y) | x in R and y in S } tupling: (x,y) projections: fst, snd **** disjoint union (coproduct) R + S = {(zero,x) | x in R} union {(one,y) | y in S} -tag injections: inR(x) = (zero,x) inS(y) = (one,y) case cases m of isR x -> ... x ... [] isS y -> ... y... end *** Functions (set morphisms) f: R -> S is a function if to each member of R, f associates exactly one member of S. (R -> S) is the arity (rank, signature) of f R is the domain (source) of f S is the codomain (range, target) of f **** extensionality for functions functions f,g: R->S equal only if for all r in R, f(r) = g(r) **** composition: (f o g): R -> T defined for g: R -> S and f: S -> T by (f o g)(x) = f(g(x)) **** properties of functions one-to-one (injective)? onto (surjective)? one-to-one and onto (bijective) identity? inverse of bijective function? set isomorphism bijective set morphism **** graph of a function graph(f:R->S) = {(x,y) | x in R} **** description of functions e.g., add: N x N -> N add(m,n) = m + n only *presents* a function **** update (cf. substitution) ([a |-> b]f)(x) = if x = a then b else f(x) other notation: f[b/a], f[a := b] ** Semantic algebras (presentation of primitive domains) give representation (domain) and signature and behavior of each operation *** equational style example (example 3.2 on p. 36) --------------------- Domain Bool Operations true: Bool false: Bool not: Bool -> Bool or: Bool -> Bool (_ -> _ [] _): for all D, Bool D D -> D Axioms for all b, b1:Bool; d1,d2: D not(true) = false not(false) = true or(true,b) = true or(false,b) = b (true -> d1 [] d2) = d1 (false -> d1 [] d2) = d2 --------------------- *** program style, example 2.1 (p. 30), better for handling errors program over the representation (most of Schmidt's) -assume already know what rep domain means, -can use lambda calculus, extended with rules for conditionals and operations of representing domain note for below: \bot = bottom, _ is subscript, except after \ where it is a strict lambda --------------------- Domain Rat = (Z x Z)_{\bot} Operations makerat: Z -> (Z -> Rat) makerat = \p.\q.(q=0) -> \bot [] (p,q) addrat: Rat -> Rat -> Rat addrat = \_(p1,q1).\_(p2,q2). ((p1*q2)+(p2*q1),q1*q2) mulrat: Rat -> Rat -> Rat mulrat = \_(p1,q1).\_(p2,q2). (p1*p2,q1*q2) Same in SML structure Rat = struct type Rat = int * int exception RatErr val makerat: int -> int -> Rat = fn p => fn q => if q = 0 then raise RatErr else (p,q) val addrat: Rat -> Rat -> Rat = fn (p1,q1) => fn (p2,q2) => ((p1*q2)+(p2*q1),q1*q2) val mulrat: Rat -> Rat -> Rat = fn (p1,q1) => fn (p2,q2) => (p1*p2,q1*q2) end; --------------------- ** Domains (not the same as sets: think of as sets with more structure) *** Primitive: Nat, Bool, Int, String, Unit, ... *** Compound (see Schmidt for notation) each has assembly operations (constructors) and disassembly operations (observers) each has an extensionality principle (=) **** products A x B -------------- if a in A and b in B, then (a,b) in A x B fst: A x B -> A snd: A x B -> B p v n is nth element of n-fold product extensionality: p1 = p2 iff fst(p1)=fst(p2) and snd(p1)=snd(p2) -------------- how would you write this in SML? example: integers as signed Nats **** sum (or coproduct) A + B -------------- inA: A -> A+B inB: B -> A+B (cases _ of isA(x) -> _ [] isB(y) -> _ end) : (A+B x (A->D) x (B->D)) -> D extensionality: s1 = s2 iff both have same tag and value -------------- what's the corresponding thing in SML? how to write in SML? example: booleans, finite lists (page 43) **** function A -> B ------------------ if E is such that for all a in A, [a/x]E in B, then \x.E in (A -> B) _(_): (A->B x A) -> B extensionality: f1 = f2 iff for all x in A, f1(x) = f2(x) ------------------ so only computable functions (\-exps) are elements of domain Warning about recursion (section 3.3) not allowed, so that mathematically definitions are well defined e.g., q(x) = x equals zero -> one [] q(x plus one) **** lifted A_{\bot} = A union {\bot} assembly principle \bot in A_{\bot} if a in A, then a in A_{\bot} ***** bottom (\bot) usually means nontermination or "no value" alternative: partial functions all other values "proper" ***** disassembly is strict lambda abstraction (\_) f: A_{\bot} -> B_{\bot} = \_x . M defined as f(\bot) = \bot f(a) = [a/x]M, if a is proper e.g, strict vs. nonstrict constant function let x=e1 in e2 means (\_x.e2)e1 read up through Schmidt's section 3.2 *** example: denotational semantics of FL design this in class (on overheads) note: also have operational semantics for FL... semantic domains (ask what each is) notice, this is not as careful in semantic algebras functionality of valuation functions? do some calculations with it. e.g., semantics of (call (proc x 1) (/ 3 0)) = \u . cases valE[[(proc x 1)]]u of ... = \u . cases inProcedure(\e.valE[[1]](extend-env u [[x]] e)) of ... = \u . cases inProcedure(\d.1) of isProcedure(p) -> ... = \u . cases valE[[(/ 3 0)]]u of ... [] isError() -> ... = \u . (\d.1) (valE[[(/ 3 0)]]u) = \u . 1 --- assuming division follows it's type = \u . inError() --- assuming valE[[(/ 3 0)]]u gives an error. other examples: (bind y 4 (+ 3 y)) (/ 3 0) translate into SML... (see file fl-semantics2.sml) valP (( Prog( CallExp( ProcExp("x", Number(1)), ArithExp(divides, Number(3), Number(1)))) )); (* val it = inInt 1 : EV *) (* But this doesn't model errors properly. *) valP (( Prog( CallExp( ProcExp("x", Number(1)), ArithExp(divides, Number(3), Number(0)))) )); (* uncaught exception Div *) **** Compositional semantics Notice how each clause in semantics of FL depends on denotations of subparts (instead of their texts) or differs depending on context => orthogonal designs for languages