-- ========================================================== --> CafeOBJ code for lecture02 -- ========================================================== -- ========================================================== --> basics of commands of CafeOBJ system -- ========================================================== -- type in the following sequence into CafeOBJ system -- and see what happen mod TEST {[ Elt ]} select TEST ? show show ? sh sh ? -- show the built-in module RAT sh NAT select NAT show show ops show sorts show rules show eqs show op (_ + _) describe op (_ + _) open NAT . show show ops show sorts show rules show eqs show op (_ + _) describe op (_ + _) close set auto context on mod TEST {[ Elt ]} set ? show switches select NAT look up Nat look up (_+_) names NAT . -- ========================================================== --> parameterized list (generic list) -- ========================================================== mod* TRIVa= {[Elt] op _a=_ : Elt Elt -> Bool {comm} .} --> parametrized list (i.e. generic list) mod! LIST (X :: TRIVa=) { [List] op nil : -> List {constr} . op _|_ : Elt.X List -> List {constr} . -- op _a=_ : List List -> Bool {comm} . eq (L:List a= L) = true . eq (nil a= (E2:Elt | L2:List)) = false . eq ((E1:Elt | L1:List) a= (E2:Elt | L2:List)) = (E1 a= E2) and (L1 a= L2) . } -- ========================================================== -- view and parameter instantiation -- ========================================================== --> Peano style natural numbers mod! PNAT { [ Nat ] op 0 : -> Nat {constr} op s_ : Nat -> Nat {constr} -- equality over Nat op _a=_ : Nat Nat -> Bool {comm} . eq (N:Nat a= N) = true . eq (0 a= s(Y:Nat)) = false . eq (s(X:Nat) a= s(Y:Nat)) = (X a= Y) . } --> view from TRIVa= to PNAT view TRIV=>PNATa= from TRIVa= to PNAT { sort Elt -> Nat, op (E1:Elt a= E2:Elt) -> (E1:Nat a= E2:Nat) } -- view TRIV=>PNATa= maps sorts/ops in TRIVa= -- to sorts/ops in PNAT --> parameter instantiation with view and renaming mod PNATa=LIST {pr( LIST(TRIV=>PNATa=) *{sort List -> NatList} ) } -- this can be written also as: make PNATa=LIST ( LIST(TRIV=>PNATa=) *{sort List -> NatList} ) -- *{sort List -> NatList} renames the sort List of -- module in the module LIST(TRIV=>PNATa=) to NatList --> testing PNATa=LIST open PNATa=LIST . parse (s 0 | nil) . ops a b : -> Nat . red (0 | s 0 | nil) a= (0 | s 0 | nil) . red (0 | s 0 | nil) a= (0 | s s 0 | nil) . red (a | b | nil) a= (a | b | nil) . red (a | b | nil) a= (0 | b | nil) . close --> All the following three view definitions --> define the view TRIV=>PNATa= also view TRIV=>PNATa= from TRIVa= to PNAT { sort Elt -> Nat, op (_ a= _) -> (_ a= _) } view TRIV=>PNATa= from TRIVa= to PNAT { sort Elt -> Nat } view TRIV=>PNATa= from TRIVa= to PNAT { } -- ========================================================== -- view calculus (or view inference) -- ========================================================== -- Do not use the charactor " -- in the comment of the following style "[comment starts The fact that the view definition with empty body view TRIV=>PNATa= from TRIVa= to PNAT {} can define a view means that the view from TRIV= to PNAT can be inferred by the CafeOBJ system without any extra information. The inference proceeds as follows. (1) (Elt -> Nat) becuae each Elt and Nat is only one sort of TRIV= and PNAT, (2) ((E1:Elt = E2:Elt) -> (E1:Nat = E2:Nat)) because these two operator have the same name and satisfies condition induced by the sort map (Elt -> Nat). -- PNAT with order-sorted signature mod! PNATord { [Zero NzNat < Nat] op 0 : -> Zero {constr} . op s_ : Nat -> NzNat {constr} . op p_ : NzNat -> Nat . eq p s N:Nat = N . op _a=_ : Nat Nat -> Bool {comm} . eq (N:Nat a= N) = true . eq (N:Nat a= N) = true . eq (0 a= s(N2:Nat)) = false . eq (s(N1:Nat) a= s(N2:Nat)) = (N1 a= N2) . } Notice that view TRIV=>PNATord from TRIVa= to PNATord {} does not work this time, for PNATord has three sorts. It is necessary to write: view TRIV=>PNATord from TRIVa= to PNATord {sort Elt -> Nat} Another way to make default view calculus work is to define principal sort of PNATord as follows. -- PNAT with order-sorted signature and principal sort mod! PNATord-ps principal-sort Nat { [Zero NzNat < Nat] op 0 : -> Zero {constr} . op s_ : Nat -> NzNat {constr} . op p_ : NzNat -> Nat . eq p s N:Nat = N . op _a=_ : Nat Nat -> Bool {comm} . eq (N:Nat a= N) = true . eq (0 a= s(N2:Nat)) = false . eq (s(N1:Nat) a= s(N2:Nat)) = (N1 a= N2) . } With principal sort declaration, view TRIV=>PNATord from TRIVa= to PNATord {} works. However, it is recommended to give sort map {sort Elt -> Nat} than declaring principal sort. Generally, the CafeOBJ system tries to calculate a view using the information, (1) Sort and operator mapping information given by body of the view definition, (2) Principal sort correspondence if a principal sort is declared in both source and/or target modules, (3) Equality of sort name and operator name (i.e. sort or operator with the same name are chosen to be a target of view/map), (4) Induced condition from sort map on rank of a target operator. comment ends]" -- ========================================================== --> on the fly view definition -- ========================================================== -- view TRIV=>PNAT= can be defined on the fly without -- giving name in the middle of instantiating the -- formal parameter TRIVa= by the actual parameter PNAT. -- > another way to define PNATa=LIST make PNATa=LIST (LIST(X <= view to PNAT {sort Elt -> Nat, op _a=_ -> _a=_}) *{sort List -> NatList}) --> yet another way to define PNATa=LIST make PNATa=LIST (LIST(PNAT{sort Elt -> Nat, op _a=_ -> _a=_}) *{sort List -> NatList}) --> yet yet another way to define PNATa=LIST make PNATa=LIST (LIST(PNAT)*{sort List -> NatList}) -- ========================================================== -- Defining view by op map with expressions -- ========================================================== -- defining op map with expression (derived op) --> view from TRIVa= to the built-in NAT view TRIV=>NAT== from TRIVa= to NAT { sort Elt -> Nat, op (E1:Elt a= E2:Elt) -> (E1:Nat == E2:Nat) } --> parameter instantiation with view make NAT==LIST (LIST(TRIV=>NAT==)) --> testing the NAT==LIST open NAT==LIST . ops a b : -> Nat . red (0 | 1 | nil) = (0 | 1 | nil) . red (0 | 1 | nil) = (0 | 2 | nil) . red (a | b | nil) = (a | b | nil) . red (a | b | nil) = (0 | b | nil) . close --> notice that the following definition of view does --> not work "[ view TRIV=>NAT from TRIV= to NAT { sort Elt -> Nat, op (_ =a _) -> (_ == _) } ]" -- it is because the rank of (_ == _) is -- *Cosmos* *Cosmos* -> Bool -- where "*Cosmos*" is the built-in universal sort select NAT show op (_ == _) -- another example --> target of an operator can be a term --> in view definition view TRIV=>NAT<=> from TRIVa= to NAT { sort Elt -> Nat, op (E1:Elt a= E2:Elt) -> ((E1:Nat <= E2:Nat) and (E1:Nat >= E2:Nat)) } --> parameter instantiation with view make NAT<=>LIST (LIST(TRIV=>NAT<=>)) --> on the fly view definition make NAT<=>LIST (LIST(NAT{sort Elt -> Nat, op (E1:Elt a= E2:Elt) -> ((E1:Nat <= E2:Nat) and (E1:Nat >= E2:Nat))})) --> testing the NAT<=>LIST open NAT<=>LIST . ops a b : -> Nat . red (0 | 1 | nil) a= (0 | 1 | nil) . red (0 | 1 | nil) a= (0 | 2 | nil) . red (a | b | nil) a= (a | b | nil) . red (a | b | nil) a= (0 | b | nil) . close -- ========================================================== --> module expressions -- ========================================================== "[comment starts A module expression is expression composed of followings five components. (1) module names (2) parameterized module names (3) view names and on-the-fly view definitions (4) renamings (5) module sums (i.e. ME1 + ME2) Module sum (_+_) is idempotent operator and satisfies the equation, eq (M:ModuleExpression + M) = M . This implies that syntactically equal module expressions shrink into one. comment ends]" --> an example of module expression -- STRING is a built-in module make NATlist+STRlist (LIST(PNAT)*{sort List -> NatList} + LIST(STRING{sort Elt -> String, op _a=_ -> string=}) *{sort List -> StringList}) --> testing of NATlist+STRlist select NATlist+STRlist red s 0 | s s 0 | nil . red "a" | "b" | nil . red "a" | "b" | nil a= "b" | nil . "[comment starts A module expression which is not a module name is called a proper module expresion. Module expression means proper module expression in the following. The followings are examples of module expressions already defined. LIST(TRIV=>PNATa=)*{sort List -> NatList}) LIST(X <= view to PNAT {sort Elt -> Nat, op (E1:Elt a= E2:Elt) -> (E1:Nat a= E2:Nat)}) LIST(PNAT {sort Elt -> Nat, op (E1:Elt a= E2:Elt) -> (E1:Nat a= E2:Nat)}) *{sort List -> NatList} LIST(PNAT) LIST(TRIV=>NAT==) LIST(PNATord{sort Elt -> Nat}) LIST(PNAT) + LIST(TRIV=>NAT==) + LIST(PNATord{sort Elt -> Nat}) LIST(PNAT) + LIST(PNAT) (this module expression equals to LIST(PNAT)) In evaluating an module expression, a new module is created each time a module sub-expression is evaluated. This implies if a module expression contains two of the same module expression, two of the same undistinguishable modules are created. This usually causes serious errors. Let assume that (i) A B are module names, and (ii) F(X :: TRIV, Y :: TRIV) is parameterized module name. Then F(F(A,B),F(A,B)) is a module expression. If this module expression is evaluated, two of the same undistinguishable modules of F(A,B) are created. This implies that, even if t1 is a term of the module F(A,B), t1 can not be parsed in F(F(A,B),F(A,B)), for there is no way to know which of the two undistinguishable modules t1 belongs. To avoid this anomaly, instead of doing, make ME (F(F(A,B),F(A,B))) do make MEsub (F(A,B)) make ME (F(MEsub,MEsub)). Doing us(ModExp) (or ex(ModExp) or inc(ModExp)) twice in the same module definition causes the same problem, and should be avoided. comment ends]" --> PAIR(X :: TRIV, Y :: TRIV) --> TRIV is a built-in module mod! PAIR (X :: TRIV, Y :: TRIV) { [Pair] op _,_ : Elt.X Elt.Y -> Pair {constr} . } --> should be avoided!! make NAT-PP-1 (PAIR(PAIR(NAT,NAT),PAIR(NAT,NAT))) select NAT-PP-1 parse (1,2) . parse ((1,2),(1,2)) . make NAT-P (PAIR(NAT,NAT)) make NAT-PP-2(PAIR(NAT-P,NAT-P)) select NAT-PP-2 parse (1,2) . parse ((1,2),(1,2)) . make 2-PNATNATsum (PAIR(NAT,NAT) + PAIR(NAT,NAT)) select 2-PNATNATsum parse (1,2) . mod 2-PNATNATpr { inc(PAIR(NAT,NAT)) inc(PAIR(NAT,NAT)) } select 2-PNATNATpr parse (1,2) . mod 2-NAT-Ppr { inc(NAT-P) inc(NAT-P) } select 2-NAT-Ppr parse (1,2) . --> an example of complex module expression make NATlistPair+NATlist+STRlist (PAIR(LIST(PNAT){sort Elt -> List}, LIST(PNAT){sort Elt -> List}) + LIST(PNAT)*{sort List -> NatList} + LIST(PNAT)*{sort List -> NatList} + LIST(STRING{sort Elt -> String, op _a=_ -> string=}) *{sort List -> StringList}) --> testing of NATlist+STRlist select NATlistPair+NATlist+STRlist parse s 0 | nil . -- this cause a parsing error, the module expression: -- PAIR(LIST(PNAT){sort Elt -> List}, -- LIST(PNAT){sort Elt -> List}) -- is a problem! Aviod this! parse (s 0 | nil):List . -- still ambiguous! parse (s 0 | nil):NatList . -- this does not cause the problem because -- LIST(PNAT)*{sort List -> NatList} + -- LIST(PNAT)*{sort List -> NatList} -- shrinks into -- LIST(PNAT)*{sort List -> NatList} parse (s 0 | nil, s 0 | nil) . red "a" | "b" | nil . red "a" | "b" | nil a= "b" | nil . --> the following complex module expression --> is better to be written as follows! -- make NATlistPair+NATlist+STRlist -- (PAIR(LIST(PNAT){sort Elt -> List}, -- LIST(PNAT){sort Elt -> List}) + -- LIST(PNAT)*{sort List -> NatList} + -- LIST(PNAT)*{sort List -> NatList} + -- LIST(STRING{sort Elt -> String, -- op _a=_ -> string=}) -- *{sort List -> StringList}) make NATlist1 (LIST(PNAT)) make NATlist2 (LIST(PNAT)*{sort List -> NatList}) make NATlist1Pair+NATlist2+STRlist (PAIR(NATlist1{sort Elt -> List},NATlist1{sort Elt -> List}) + NATlist2 + LIST(STRING{sort Elt -> String, op _a=_ -> string=}) *{sort List -> StringList}) --> testing of NATlist+STRlist select NATlist1Pair+NATlist2+STRlist parse s 0 | nil . -- this still cause a parsing error, the module expression: parse (s 0 | nil):List . parse (s 0 | nil):NatList . parse (s 0 | nil, s 0 | nil) . red "a" | "b" | nil . red "a" | "b" | nil a= "b" | nil . -- ========================================================== --> order-sorted parameterized list and error handling -- ========================================================== --> parametrized list with order-sort --> notice that TRIV is used instead of TRIVa= mod! LISTord (X :: TRIV) { [Nil NnList < List] op nil : -> Nil {constr} . op _|_ : Elt.X List -> NnList {constr} . -- taking head of list op hd_ : NnList -> Elt.X . eq hd (E1:Elt | L1:List) = E1 . -- taking tail of list op tl_ : NnList -> List . eq tl (E1:Elt | L1:List) = L1 . -- equality on the sort List -- op _=_ : List List -> Bool {comm} . -- eq (L = L) = true . eq (nil = (E2:Elt | L2:List)) = false . eq ((E1:Elt | L1:List) = (E2:Elt | L2:List)) = (E1 = E2) and (L1 = L2) . } -- testing LISTord open LISTord . parse hd nil . parse tl nil . ops a b : -> Elt . red tl (a | b | nil) . red tl tl (a | b | nil) . red hd tl (a | b | nil) . red hd tl tl (a | b | nil) . red tl tl tl (a | b | nil) . close -- (hd nil) and (tl nil) are terms of error sorts. This is -- an example of error handling with order-sorted signature -- ========================================================== --> verification on parametrized module -- ========================================================== -- Verifications can be done on a parametrized module and -- the achieved verificaitons are effective for all -- instanciated modules of the parametrized module. --> parametrized list (i.e. generic list) --> notice that TRIV is used instead of TRIVa= mod! LIST' (X :: TRIV) { [List] op nil : -> List {constr} . op _|_ : Elt.X List -> List {constr} . -- eq (nil = (E2:Elt | L2:List)) = false . eq ((E1:Elt | L1:List) = (E2:Elt | L2:List)) = (E1 = E2) and (L1 = L2) . } --> append _@_ over List mod! LIST@(X :: TRIV) { inc(LIST'(X)) -- append operation over List op _@_ : List List -> List . eq [@1]: nil @ L2:List = L2 . eq [@2]: (E:Elt | L1:List) @ L2:List = E | (L1 @ L2) . } --> testing open (LIST@(NAT)) . ops a b : -> Nat . red (0 | 1 | nil) @ (0 | 1 | nil) . red (a | b | nil) @ (a | b | nil) . close --> using trace command open LIST@ . ops a b c : -> Elt . set trace on red (a | b | c | nil) @ (a | b | c | nil) . set trace off set trace whole on red (a | b | c | nil) @ (a | b | c | nil) . set trace whole off close --> predicate about _@_ mod! PRED-LIST@(X :: TRIV) { inc(LIST@(X)) -- nil is right identity of _@_ op @ri : List -> Bool . eq @ri(L1:List) = ((L1:List @ nil) = L1) . -- _@_ is associative op @assoc : List List List -> Bool . eq @assoc(L1:List,L2:List,L3:List) = ((L1 @ L2) @ L3 = L1 @ (L2 @ L3)) . } -- ========================================================== --> Property of PRED-LIST@ --> \forall L1:List.((L1 @ nil) = L1) --> (i.e. @ri(L:Nat) = true) -- Proof: By induction on L1. -- I Base case open PRED-LIST@ . -- check red @ri(nil) . close -- II Induction case open PRED-LIST@ . -- arbitrary values op l : -> List . -- induction hypothesis eq (l @ nil) = l . -- check red @ri(`e:Elt | l) . close -- --> QED -- ========================================================== -- ========================================================== -- Property of PRED-LIST@ --> \forall L1,L2,L3:List.((L1 @ L2) @ L3 = L1 @ (L2 @ L3)) -- (i.e. @assoc(L1:List,L2:List,L3:List) = true) -- Proof: By induction on L1. -- I Base case open PRED-LIST@ . -- check red @assoc(nil,`l2:List,`l3:List) . close -- II Induction case open PRED-LIST@ . -- arbitrary values op l1 : -> List . -- induction hypothesis eq ((l1 @ L2:List) @ L3:List) = (l1 @ (L2 @ L3)) . -- check red @assoc(`e:Elt | l1,`l2:List,`l3:List) . close -- --> QED -- ========================================================== -- ========================================================== --> LIST with associative append _@_ --> and reverse operation of lists -- ========================================================== --> list with associative append _@_ mod! LIST@a(X :: TRIV) { inc(LIST'(X)) -- notice that associativity {assoc} -- and right identity [@3] is already proved op _@_ : List List -> List {assoc} . eq [@1]: nil @ L2:List = L2 . eq [@2]: (E:Elt | L1:List) @ L2:List = E | (L1 @ L2) . eq [@3]: L1:List @ nil = L1 . } --> LIST with reverse operations mod! LISTrev(X :: TRIV) { inc(LIST@a(X)) -- one argument reverse operation op rev1 : List -> List . eq rev1(nil) = nil . eq rev1(E:Elt | L:List) = rev1(L) @ (E | nil) . -- two arguments reverse operation op rev2 : List -> List . -- auxiliary function for rev2 op sr2 : List List -> List . eq rev2(L:List) = sr2(L,nil) . eq sr2(nil,L2:List) = L2 . eq sr2(E:Elt | L1:List,L2:List) = sr2(L1,E | L2) . } --> properties about LISTrev mod! PRED-LISTrev(X :: TRIV) { inc(LISTrev(X)) -- rev1 distributes over _@_ reversely op rev1@ : List List -> Bool . eq rev1@(L1:List,L2:List) = (rev1(L1 @ L2) = rev1(L2) @ rev1(L1)) . -- rev1rev1 is identity function op rev1rev1 : List -> Bool . eq rev1rev1(L:List) = (rev1(rev1(L)) = L) . -- sr2 with _@_ op sr2@ : List List List -> Bool . eq sr2@(L1:List,L2:List,L3:List) = (sr2(L1,L2) @ L3 = sr2(L1,L2 @ L3)) . -- rev1=rev2 op rev1=rev2 : List -> Bool . eq rev1=rev2(L:List) = (rev1(L) = rev2(L)) . } -- ========================================================== -- end end end -- ==========================================================