CS 541 Lecture -*- Outline -*- * OBJ, an equational-logic programming language OBJ3 (1989) is latest implementation (OBJ1 ~ 1983, OBJ2 ~ 1984) ** What to look for *** relationships to other topics how is it declarative? how does it differ from functional programming? (no first class functions for one thing) how is it like operational semantics? data abstraction? *** features: fancy (mixfix) syntax term rewriting type checking (sorting, subsorts) parameterization (generics), views, theories ** Modules and Generics *** Modules are either objects or theories **** Objects contain executable code begin with obj, end with endo comments: *** and ***> (prints) ---------------- obj SIMPLE-LIST-OF-INT is *** header: name, imported module list protecting INT . sort List . *** signature: sorts, subsorts, operations subsort Int < List . op cons : Int List -> List . op length : List -> Int . var I : Int . *** body: equations var L : List . eq length(I) = 1 . eq length(cons(I, L)) = 1 + length(L) . endo ---------------- ***** Operational semantics is term rewriting. equations are thought of as reduction rules (reduce lhs to rhs) set trace on . reduce length(cons(3,4)) . ==> 1 + length(4) ==> 1 + 1 ==> 2 note: variables in rhs must be subset of those in lhs (this is a crucial difference from logic programming) e.g., eq 1 = length(I) doesn't work ***** Modules can be imported in other modules protecting: no new terms of imported sorts (no junk) and no identification of terms of imported sorts (no confusion) extending: no confusion using: no guarantees at all ------------ obj LISP-LIST-OF-INT is extending SIMPLE-LIST-OF-INT . op nil : -> List . op car : List -> Int . op cdr : List -> List . var I : Int . var L : List . eq car(nil) = 0 . eq car(I) = I . eq car(cons(I,L)) = I . eq cdr(nil) = nil . eq cdr(I) = nil . eq cdr(cons(I,L)) = L . endo ------------ variations: could use subsorting to handle errors better how does this compare with inheritance? **** Theories describe parameters e.g. LIST[INT], SORTING[INT] will sort lists of integers. ------------------ theory TRIV is *** built-in theory sort Elt . endth obj LIST[X :: TRIV] is *** in file list-parameterized-example.obj protecting NAT . sort List . subsort Elt < List . op cons : Elt List -> List . op length : List -> Nat . var E : Elt . var L : List . eq length(E) = 1 . eq length(cons(E, L)) = 1 + length(L) . endo make LIST-OF-INT is LIST[INT] endm ------------------ allows lists of various kinds. To instantiate a parameterized module, have to provide actuals that satisfy the formal requirement theories. (only syntax is checked) ---------- theory POSET is protecting BOOL . sort Elt . op _<_ : Elt Elt -> Bool . vars E E' E'' : Elt . eq E < E = false . ceq E < E'' = true if (E < E' and E' < E'') . endth obj SORTING [ELT :: POSET] is *** ... endo ---------- so one can the the body of SORTING using <. note the infix syntax, conditional equation. *** Views map from formals to actuals (signature morphisms) **** defaults sorts map to sorts of same name. principal sorts map to principal sorts (first one) operations map to operations with same name ---------- view INT-DEFAULT from POSET to INT is sort Elt to Int . op _<_ to _<_ . endv ---------- **** can explicitly construct and name views ---------- view INT-DESC from POSET to INT is sort Elt to Int . vars X Y : Elt . op X < Y to Y < X . endv ---------- INT-DESC views integers as a poset in reverse order **** instantiation of parameterized modules uses a view ---------- make SORT-INT-LT is SORTING[INT-DESC] endm ---------- equivalent to obj SORT-INT-LT is protecting SORTING[INT-DESC] . endo default view is used if another module is provided what was used above for LIST[INT]? view from TRIV to INT is sort Elt to Int . endv *** Module expressions (renamings) allow one to define, construct and instantiate complex combinations of modules allow one to modify modules (to allow wider use). basic module expressions are constants: built-ins: TRUTH-VALUE, TRUTH, BOOL, NAT, NZNAT, INT, ID, QIDL, FLOAT renamings: can change names of sorts and operations (sort Elt to Int) (op _<_ to _eq_) used following a * ------------- theory EQV is using PREORD*(op _<_ to _eqv_) vars E1 E2 : Elt . eq (E1 eqv E2) = (E2 eqv E1) . endth ------------- sums: use + to combine modules (so can import or use all at once) ---------- make SORT-LIST-INT is SORTING-INT-LT + LIST-OF-INT endm ---------- ** Subsorts and exceptions what to do about limit cases? e.g., car of a single-element or empty list top of empty stack? divison by zero, etc. *** leave them undefined --------------- obj INCOMPLETE-LIST-OF-INT is extending SIMPLE-LIST-OF-INT . op nil : -> List . op car : List -> Int . op cdr : List -> List . var I : Int . var L : List . eq car(I) = I . eq car(cons(I,L)) = I . eq cdr(I) = nil . eq cdr(cons(I,L)) = L . endo --------------- then car(nil) is an Int, but it's not equal to other Int. so have added more terms of sort Int. *** use an error element (identify all error terms) --------------- var I : Int . var L : List . eq car(nil) = error . eq cdr(nil) = error . --------------- what is the sort of error? (could use errorInt, errorList) has to be Int so what is 3 + error? (it's another Int...) if try to add equations I+error = error. then get inconsistency (0 = 1)... *** order-sorted algebra, with subsorts subsort is a subset of its supersort (carrier sets) e.g., NeList is subset of List ---------------- obj LIST-EXTENDED[X :: TRIV] is extending LIST[X] . sort NeList . subsorts Elt < NeList < List . op nil : -> List . op car : NeList -> Elt . op cdr : NeList -> List . op cons : Elt List -> NeList . var E : Elt . var L : List . eq car(E) = E . eq car(cons(E,L)) = E . eq cdr(E) = nil . eq cdr(cons(E,L)) = L . endo ---------------- now car(nil) is an error (not an int), since nil has wrong sort. don't have to define 3 + car(nil) see: stack example on page 11 of OBJ ref. material.