CSC 530 Lecture Notes Week 10
Algebraic Semantics
obj STACK is sort Stack .
    protecting NAT .
    op push : Stack Nat -> Stack .
    op pop : Stack -> Stack .
    op top : Stack -> Nat .
    op emptyStack : -> Stack .
    op emptyElem : -> Nat .
    var S : Stack .
    var E E' : Nat .
    eq pop(emptyStack) = emptyStack .
    eq pop(push(S, E)) = S .
    eq top(emptyStack) = emptyElem .
    eq top(push(S, E)) = E .
endo
in Stack
***
*** obj MAIN is comparable to a class or module declaration.
obj MAIN is
    *** The protecting clause in OBJ is like importing.
    protecting STACK .
    protecting INT .
    *** An OBJ op primarily declares functions, such as main here.
    op main : -> Stack .
    *** An OBJ parameterlesss op decl can also be used to declare a single-
    *** assignment variable of a particular type
    op s1 : -> Stack .
    op s2 : -> Stack .
    op i : -> Int .
    *** OBJ equations declare what the program does.  Typically, they're used
    *** as in object STACK to define behavior of ADT operations.  They can also
    *** be used as below to simulate a form of single assignment programming.
    *** E.g., the immediately following four equations simulate the following
    *** ML-style let block:
    ***
    eq s1 = pop(push(push(push(emptyStack, 1), 2), 3)) .
    eq i = top(push(push(push(emptyStack, 1), 2), 3)) + 1 .
    eq s2 = push(push(s1, i), 5) .
    eq main = pop(s2) .
endo
*** The following executes program main
reduce main .
*** The result of execution is the stack push(push(push(emptyStack,1),2),4).
obj LIST is sort List . protecting INT . op car : List -> Int . op cdr : List -> List . op cons : Int List -> List . op append : List List -> List . op emptyList : -> List . var e : Int . var l l1 l2 : List . eq car(cons(e,l)) = e . eq cdr(cons(e,l)) = l . eq car(append(l1,l2)) = car(l1) . eq cdr(append(l1,l2)) = append(cdr(l1),l2) . eq append(emptyList,l) = l . eq append(l,emptyList) = l . endo
th ELEM is sort Elem .
endth
view ELEM-TO-NAT from ELEM to NAT is
    sort Elem to Nat .
endv
obj SET[EL :: ELEM] is sort Set .
    op insert : Set Elem -> Set .
    op delete : Set Elem -> Set .
    op find : Set Elem -> Bool .
    op emptyset : -> Set .
    op equal : Set Set -> Bool .
    var S S' : Set .
    var E E' : Elem .
    eq find(emptyset, E) = false .
    eq find(insert(S, E), E') =
        if E == E' then true else find(S, E') fi .
    eq delete(emptyset, E) = emptyset .
    eq delete(insert(S, E), E') =
        if E == E'
        then delete(S, E')
        else insert(delete(S, E'), E)
        fi .
    eq equal(emptyset, emptyset) = true .
    eq equal(emptyset, insert(S, E)) = false .
    eq equal(insert(S, E), emptyset) = false .
    eq equal(S, insert(S', E)) =
        if find(S, E)
        then equal(delete(S, E), delete(S', E))
        else false
        fi .
endo
in List-Int
obj BinSearchTree is sort BST .
  protecting LIST + INT .
  op makeTree : Int BST BST -> BST .
  op root : BST -> Int .
  op find : BST Int -> BST .
  op del : BST Int -> BST .
  op reinsert : BST BST -> BST .
  op enum : BST -> List .
  op emptyTree : -> BST .
  op legalBST : BST -> Bool .   *** Optional (see below)
  op insert : BST Int -> BST .  *** Optional (ibid.)
  var b b1 b2 : BST .
  var e e1 e2 : Int .
  eq root(makeTree(e, b1, b2)) = e .
  eq find(emptyTree,e) = emptyTree .
  eq find(makeTree(e1,b1,b2),e2) =
    if legalBST(makeTree(e1,b1,b2))
    then if e1 == e2 then makeTree(e1,b1,b2)
         else if e2 < e1 then find(b1,e2)
              else find(b2,e2) fi fi
    else
      emptyTree
    fi .
  eq del(emptyTree,e) = emptyTree .
  eq del(makeTree(e1,b1,b2),e2) =
    if e1 == e2 then reinsert(b1,b2)
    else if e2 < e1 then makeTree(e1,del(b1,e2),b2)
         else makeTree(e1,b1,del(b2,e2)) fi
    fi .
  eq reinsert(b,makeTree(e,b1,b2)) =
    if b1 == emptyTree
    then makeTree(e,b,b2) else makeTree(e,reinsert(b,b1),b2) fi .
  eq reinsert(b,emptyTree) = b .
  eq reinsert(emptyTree,b) = b .
  eq enum(makeTree(e,b1,b2)) = append(enum(b1), cons(e, enum(b2))) .
  eq enum(emptyTree) = emptyList .
  *** ALTERNATIVES FOR OPTIONAL WELL-FORMEDNESS CHECKING
  *** Eqns for legalBST could be expanded to check search tree well-formedness.
  eq legalBST(makeTree(e,b1,b2)) = true .
  *** Alternatively, eqns for an insert op could enforce well-formedness:
  eq insert(emptyTree,e) = makeTree(e,emptyTree,emptyTree) .
  eq insert(makeTree(e1,b1,b2),e2) =
    if e1 == e2 then makeTree(e1,b1,b2)
    else
      if e2 < e1
      then makeTree(e1,insert(b1,e2),b2)
      else makeTree(e1,b1,insert(b2,e2))
      fi
    fi .
endo
*** Instantiate a BinSearchTree object
make BST-INT is BinSearchTree endm
*** Do some sample reductions
reduce del(
  makeTree(5,
    makeTree(2,
      makeTree(1,emptyTree,emptyTree),
        makeTree(3,emptyTree,emptyTree)),
    makeTree(10,
      makeTree(6,emptyTree,emptyTree),
      makeTree(12,emptyTree,emptyTree))),
  5) .
*** Result is:
*** makeTree(10,
***   makeTree(6,
***     makeTree(2,
***       makeTree(1,emptyTree,emptyTree),
***       makeTree(3,emptyTree,emptyTree)),
***     emptyTree),
***   makeTree(12,emptyTree,emptyTree))
reduce enum(
  makeTree(5,
    makeTree(2,
         makeTree(1,emptyTree,emptyTree),
         makeTree(3,emptyTree,emptyTree)),
    makeTree(10,
         makeTree(6,emptyTree,emptyTree),
         makeTree(12,emptyTree,emptyTree)))
  ) .
*** Result is:
*** append(append(cons(1,emptyList),cons(2,cons(3,emptyList))),
***    cons(5,append(cons(6,emptyList),cons(10,cons(12,emptyList)))))
reduce car(cdr(cdr(
 enum(
  makeTree(5,
    makeTree(2,
         makeTree(1,emptyTree,emptyTree),
         makeTree(3,emptyTree,emptyTree)),
    makeTree(10,
         makeTree(6,emptyTree,emptyTree),
         makeTree(12,emptyTree,emptyTree)))
  )))) .
*** Result is: 3
th ELEM is sort Elem .
endth
view ELEM-TO-NAT from ELEM to NAT is
    sort Elem to Nat .
endv
obj LIST[E :: ELEM] is sort List .
   op car : List -> Elem .
   op cdr : List -> List .
   op cons : Elem List -> List .
   op append : List List -> List .
   op emptyList : -> List .
   var e : Elem .
   var l l1 l2 : List .
   eq car(cons(e,l)) = e .
   eq cdr(cons(e,l)) = l .
   eq car(append(l1,l2)) = car(l1) .
   eq cdr(append(l1,l2)) = append(cdr(l1),l2) .
endo
make LIST-NAT is LIST[ELEM-TO-NAT] endm
make LIST-INT is LIST[ELEM-TO-NAT] endm
in list2 th POSET is sort Elt . op _<_ : Elt Elt -> Bool . vars E1 E2 E3 : Elt . eq E1 < E1 = false . cq E1 < E3 = true if E1 < E2 and E2 < E3 . endth th TOSET is using POSET . vars E1 E2 E3 : Elt . cq E1 < E2 or E2 < E1 = true if E1 =/= E2 . endth obj BUBBLES[X :: TOSET] is protecting LIST[X] . op sorting_ : List -> List . op sorted_ : List -> Bool . vars L L' L'' : List . vars E E' : Elt . cq sorting L = L if sorted L . cq sorting L E E' L'' = sorting L E' E L'' if E' < E . eq sorted nil = true . eq sorted E = true . cq sorted E E' L = sorted E' L if E < E' or E == E' . endo in bubbles view NATD from POSET to NAT is vars L1 L2 : Elt . op L1 < L2 to L1 divides L2 and L1 =/= L2 . endv reduce in A is BUBBLES[NAT] : sorting(18 5 6 3) . ***> should be: 3 5 6 18 reduce sorting(8 5 4 2) . ***> should be: 2 4 5 8 reduce in B is BUBBLES[NATD] : sorting(18 5 6 3) . ***> mightnt contain: 3 6 18 reduce sorting(8 5 4 2) . ***> mightnt contain: 2 4 8
in lib/list
in lib/array
*** the expressions of Fun
obj EXP is dfn Env is ARRAY[QID,INT] .
  sorts IntExp BoolExp .
  subsorts Int Id < IntExp .
  subsorts Bool < BoolExp .
  ops (_and_)(_or_) : BoolExp BoolExp -> BoolExp .
  op not_ : BoolExp -> BoolExp .
  op _<_ : IntExp IntExp -> BoolExp .
  op _=_ : IntExp IntExp -> BoolExp .
  op if_then_else_fi : BoolExp IntExp IntExp -> IntExp .
  ops (_+_)(_-_)(_*_) : IntExp IntExp -> IntExp .
  op [[_]]_ : IntExp Env -> Int .
  op [[_]]_ : BoolExp Env -> Bool .
  var N : Int .         var T : Bool .
  vars E E' : IntExp .  vars B B' : BoolExp .
  var I : Id .          var V : Env .
  eq [[ N ]] V = N .
  eq [[ I ]] V  = V [ I ] .
  eq [[ E + E' ]] V = ([[ E ]] V) + ([[ E' ]] V) .
  eq [[ E - E' ]] V = ([[ E ]] V) - ([[ E' ]] V) .
  eq [[ E * E' ]] V = ([[ E ]] V) * ([[ E' ]] V) .
  eq [[ T ]] V = T .
  eq [[ E < E' ]] V = ([[ E ]] V) < ([[ E' ]] V) .
  eq [[(E = E')]] V = ([[ E ]] V) == ([[ E' ]] V) .
  eq [[ B and B' ]] V = ([[ B ]] V) and ([[ B' ]] V) .
  eq [[ B or  B' ]] V = ([[ B ]] V) or  ([[ B' ]] V) .
  eq [[ not B ]] V = not([[ B ]] V) .
  eq [[ if B then E else E' fi ]] V =
        if [[ B ]] V then [[ E ]] V else [[ E' ]] V fi .
endo
*** the statements of Fun
obj STMT is sort Stmt .
  protecting EXP .
  op _;_ : Stmt Stmt -> Stmt [assoc] .
  op _:=_ : Id IntExp -> Stmt .
  op while_do_od : BoolExp Stmt -> Stmt .
  op [[_]]_ : Stmt Env -> Env .
  vars S S' : Stmt .    var V : Env .
  var E : IntExp .      var B : BoolExp .
  var I : Id .
  eq [[ I := E ]] V = put(I,[[ E ]] V, V) .
  eq [[ S ; S' ]] V = [[ S' ]] [[ S ]] V .
  eq [[ while B do S od ]] V = if [[ B ]] V then
     [[ while B do S od ]] [[ S ]] V else V fi .
endo
*** evaluation of Fun programs
obj FUN is sorts Fun Init .
  protecting STMT .
  dfn IdList is LIST[QID] .
  dfn IntList is LIST[INT] .
  dfn InitList is (LIST *(op nil to nil-init, op (__) to (_;_)))[Init] .
  op _initially_ : Id IntExp -> Init [prec 1].
  op fun _ _ is vars _ body: _ : Id IdList InitList Stmt -> Fun .
  op [[_:=_]]_ : IdList IntList Env -> Env .
  op [[_]]_ : InitList Env -> Env .
  op [[_]][_]_ : Fun Env IntList -> Env .
  op [[_]]_ : Fun IntList -> Int .
  op wrong#args : -> Env .   *** err-op
  vars I F : Id .     var Is : IdList .
  var N : Int .       var Ns : IntList .
  var E : IntExp .    var INs : InitList .
  var S : Stmt .      var V : Env .
  eq [[ nil-init ]] V = V .
  eq [[(I initially E); INs ]] V = [[ INs ]] [[ I := E ]] V .
  eq [[ I Is := N Ns ]] V = ([[ I := N ]] ([[ Is := Ns ]] V)).STMT .
  eq [[(nil).IdList := (nil).IntList ]] V = V .
  eq [[ fun F(Is) is vars nil-init body: S ]][ V ](Ns) = [[ S ]] V .
  eq [[ fun F(Is) is vars INs body: S ]][ V ](Ns) =
        [[ S ]] [[ INs ]] [[ Is := Ns ]] V .
  eq [[ fun F(Is) is vars INs body: S ]](Ns) =
        [[ fun F(Is) is vars INs body: S ]][ nilArr ](Ns) [ F ] .
  cq [[ Is := Ns ]] V = wrong#args if | Is | =/= | Ns | .  *** err-qn
endo
*** pow(n m) finds the nth power of m for positive n or 0
reduce [[ fun 'pow('n 'm) is vars 'pow initially 1 body:
          while 0 < 'n do ('pow := 'pow * 'm);('n := 'n - 1) od ]](4 2) .
***> should be: 16
*** factorial of n
reduce [[ fun 'fac('n) is vars ('fac initially 1);('i initially 0) body:
          while 'i < 'n do ('i := 'i + 1); ('fac := 'i * 'fac) od ]](5) .
***> should be: 120
*** max finds the maximum of a list of three numbers
reduce [[ fun 'max('a 'b 'c) is vars 'n initially 2 body:
          ('max := 'a); while 0 < 'n do
          ('n := 'n - 1); ('x := 'b); ('b := 'c);
          ('max := if 'x < 'max then 'max else 'x fi) od ]](3 123 32) .
***> should be: 123
obj NAT is sort Nat . op 0 : -> Nat . op s_ : Nat -> Nat [prec 1] . op _+_ : Nat Nat -> Nat [assoc comm prec 3] . vars M N : Nat . eq M + 0 = M . eq M + s N = s(M + N). op _*_ : Nat Nat -> Nat [prec 2] . eq M * 0 = 0 . eq M * s N = M * N + M . endo obj VARS is protecting NAT . ops m n : -> Nat . endo ***> first show two lemmas, 0*n=0 and sm*n=m*n+n ***> base for first lemma reduce 0 * 0 == 0 . ***> induction step for first lemma obj HYP1 is using VARS . eq 0 * n = 0 . endo reduce 0 * s n == 0 . *** thus we can assert obj LEMMA1 is protecting NAT . vars N : Nat . eq 0 * N = 0 . endo ***> base for second lemma reduce in VARS + LEMMA1 : s n * 0 == n * 0 + 0 . ***> induction step for second lemma obj HYP2 is using VARS . eq s m * n = m * n + n . endo reduce s m * s n == (m * s n)+ s n . *** so we can assert obj LEMMA2 is protecting NAT . vars M N : Nat . eq s M * N = M * N + N . endo obj SUM is protecting NAT . op sum : Nat -> Nat . var N : Nat . eq sum(0) = 0 . eq sum(s N) = s N + sum(N) . endo ***> show sum(n)+sum(n)=n*sn ***> base case reduce in SUM + LEMMA1 : sum(0) + sum(0) == 0 * s 0 . ***> induction step obj HYP is using SUM + VARS . eq sum(n) + sum(n) = n * s n . endo reduce in HYP + LEMMA2 : sum(s n) + sum(s n) == s n * s s n .
in list th FN is sort S . op f : S -> S . endth obj MAP[F :: FN] is protecting LIST[F] . op map : List -> List . var X : S . var L : List . eq map(nil) = nil . eq map(X L) = f(X) map(L) . endo in map obj FNS is protecting INT . ops (sq_)(dbl_)(_*3) : Int -> Int . var N : Int . eq sq N = N * N . eq dbl N = N + N . eq N *3 = N * 3 . endo reduce in MAP[(sq_).FNS] : map(0 nil 1 -2 3) . ***> should be: 0 1 4 9 reduce in MAP[(dbl_).FNS] : map(0 1 -2 3) . ***> should be: 0 2 -4 6 reduce in MAP[(_*3).FNS] : map(0 1 -2 nil 3) . ***> should be: 0 3 -6 9