-- ========================================================== --> cafeobj codes for lecture/lab2 -- ========================================================== -- ========================================================== --> 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 built-in module NAT show 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 -- ========================================================== --> parameterized list (generic list) -- ========================================================== --> elements with equality predicate mod* TRIV= { [Elt] op _=_ : Elt Elt -> Bool {comm} . ** the above declaration is necessary ** for view inference } --> parametrized list (i.e. generic list) mod! LIST (X :: TRIV=) { [List] op nil : -> List {constr} . op _|_ : Elt.X List -> List {constr} . -- -- variables declaration vars L L1 L2 : List . vars E1 E2 : Elt . -- equality on the sort List eq (nil = (E2 | L2)) = false . eq ((E1 | L1) = (E2 | L2)) = (E1 =.X E2) and (L1 = L2) . } -- Elt.X indicates Elt in (X :: TRIV=) -- (_ =.X _) indicates (_ = _) in (X :: TRIV=) select TRIV= show op _=_ describe mod tree TRIV= select LIST show op _=_ -- ========================================================== -- view and parameter instantiation -- ========================================================== --> Peano style natural numbers mod! PNAT { [ Nat ] op 0 : -> Nat {constr} op s_ : Nat -> Nat {constr} -- equality over Nat op _=_ : Nat Nat -> Bool {comm} ** this declaration is necessary ** for view inference -- eq (0 = s(Y:Nat)) = false . eq (s(X:Nat) = s(Y:Nat)) = (X = Y) . } --> view from TRIV= to PNAT view TRIV=>PNAT= from TRIV= to PNAT { sort Elt -> Nat, op (E1:Elt = E2:Elt) -> (E1:Nat = E2:Nat) } -- view TRIV=>PNAT= maps sorts/ops in TRIV= -- to sorts/ops in PNAT --> parameter instantiation with view and renaming mod PNAT=LIST {pr( LIST(TRIV=>PNAT=) *{sort List -> NatList} ) } -- this can be written also as: make PNAT=LIST ( LIST(TRIV=>PNAT=) *{sort List -> NatList} ) -- *{sort List -> NatList} renames the sort List of -- module in the module LIST(TRIV=>PNAT=) to NatList --> testing PNAT=LIST open PNAT=LIST . parse (s 0 | nil) . ops a b : -> Nat . red (0 | s 0 | nil) = (0 | s 0 | nil) . red (0 | s 0 | nil) = (0 | s s 0 | nil) . red (a | b | nil) = (a | b | nil) . red (a | b | nil) = (0 | b | nil) . close --> the following three views definitions --> define the view TRIV=>PNAT= also --> by using "view inference" view TRIV=>PNAT= from TRIV= to PNAT { sort Elt -> Nat, op (_ = _) -> (_ = _) } view TRIV=>PNAT= from TRIV= to PNAT { sort Elt -> Nat } view TRIV=>PNAT= from TRIV= to PNAT { } -- ========================================================== -- view inference (or view calculus) -- ========================================================== #| comment starts The fact that the view definition with empty body view TRIV=>PNAT= from TRIV= 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 _=_ : Nat Nat -> Bool {comm} . eq (0 = s(N2:Nat)) = false . eq (s(N1:Nat) = s(N2:Nat)) = (N1 = N2) . } Notice that view TRIV=>PNATord from TRIV= to PNATord {} does not work this time, for PNATord has three sorts. It is necessary to write: view TRIV=>PNATord from TRIV= 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 _=_ : Nat Nat -> Bool {comm} . -- eq (0 = s(N2:Nat)) = false . eq (s(N1:Nat) = s(N2:Nat)) = (N1 = N2) . } With principal sort declaration, view TRIV=>PNATord-ps from TRIV= to PNATord-ps {} 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 TRIV= by the actual parameter PNAT. -- > another way to define PNAT=LIST make PNAT=LIST (LIST(X <= view to PNAT {sort Elt -> Nat, op _=_ -> _=_}) *{sort List -> NatList}) --> yet another way to define PNAT=LIST make PNAT=LIST (LIST(PNAT{sort Elt -> Nat, op _=_ -> _=_}) *{sort List -> NatList}) --> yet yet another way to define PNAT=LIST make PNAT=LIST (LIST(PNAT)*{sort List -> NatList}) -- ========================================================== -- Defining view by op map with expressions -- ========================================================== -- defining op map with expression (derived op) --> view from TRIV= to the built-in NAT view TRIV=>NAT== from TRIV= to NAT { sort Elt -> Nat, op (E1:Elt = 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 _=_ -> _==_ } -- -- it is because the rank of built-in predicate _==_ 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 TRIV= to NAT { sort Elt -> Nat, op (E1:Elt = 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 = 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) = (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 -- ========================================================== --> 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 (E1:Elt = E2:Elt) -> string=(E1:String,E2:String)}) *{sort List -> StringList}) --> testing of NATlist+STRlist open NATlist+STRlist . red s 0 | s s 0 | nil . red "a" | "b" | nil . red "a" | "b" | nil = "b" | nil . -- op s : -> String . red "a" | "b" | nil = s | "b" | nil . close #| 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=>PNAT=)*{sort List -> NatList}) LIST(X <= view to PNAT {sort Elt -> Nat, op (E1:Elt = E2:Elt) -> (E1:Nat = E2:Nat)}) LIST(PNAT {sort Elt -> Nat, op (E1:Elt = E2:Elt) -> (E1:Nat = 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 a 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, and should be avoided. 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 pr(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))) |# 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 { pr(PAIR(NAT,NAT)) pr(PAIR(NAT,NAT)) } select 2-PNATNATpr parse (1,2) . mod 2-NAT-Ppr { pr(NAT-P) pr(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 (E1:Elt = E2:Elt) -> string=(E1:String,E2:String)}) *{sort List -> StringList}) --> testing of NATlistPair+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):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 = "b" | nil . -- ========================================================== --> order-sorted parameterized list and error handling -- ========================================================== --> parametrized list with order-sort mod! LISTord (X :: TRIV=) { [NnList < List] op nil : -> List {constr} . op _|_ : Elt.X List -> NnList {constr} . -- -- variables declaration vars L L1 L2 : List . vars E1 E2 : Elt . -- taking head of list op hd_ : NnList -> Elt.X . eq hd (E1 | L1) = E1 . -- taking tail of list op tl_ : NnList -> List . eq tl (E1 | L1) = L1 . -- equality on the sort List eq (nil = (E2 | L2)) = false . eq ((E1 | L1) = (E2 | L2)) = (E1 =.X 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 valid for all -- instanciated modules of the parametrized module. --> append _@_ over List mod! LIST@(X :: TRIV=) { pr(LIST(X)) -- append operation over List op _@_ : List List -> List . var E : Elt . vars L1 L2 : List . eq [@1]: nil @ L2 = L2 . eq [@2]: (E | L1) @ L2 = E | (L1 @ L2) . } --> testing open (LIST@(PNAT)) . ops a b : -> Nat . red (0 | s 0 | nil) @ (0 | s 0 | 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=) { pr(LIST@(X)) -- CafeOBJ variables vars L1 L2 L3 : List . -- nil is right identity of _@_ op @ri : List -> Bool . eq @ri(L1) = ((L1 @ nil) = L1) . -- _@_ is associative op @assoc : List List List -> Bool . eq @assoc(L1,L2,L3) = ((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 e : -> Elt.X . op l1 : -> List . -- check red @ri(l1) implies @ri(e | l1) . 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@ . -- arbitrary values ops l2 l3 : -> List . -- check red @assoc(nil,l2,l3) . close -- II Induction case open PRED-LIST@ . -- arbitrary values op e : -> Elt.X . ops l1 l2 l3 : -> List . -- induction hypothesis, -- i.e. @assoc(l1,L2:List,L3:List) = true eq (l1 @ L2:List) @ L3:List = l1 @ (L2 @ L3) . -- check red @assoc(e | l1,l2,l3) . close -- --> QED -- ========================================================== -- ========================================================== --> LIST with associative append _@_ --> and reverse operation of lists -- ========================================================== --> list with associative append _@_ mod! LIST@a(X :: TRIV=) { pr(LIST(X)) -- notice that associativity {assoc} -- and right identity [@3] is already proved op _@_ : List List -> List {assoc} . vars L1 L2 : List . var E : Elt.X . eq [@1]: nil @ L2 = L2 . eq [@2]: (E | L1) @ L2 = E | (L1 @ L2) . eq [@3]: L1 @ nil = L1 . } --> LIST with reverse operations mod! LISTrev(X :: TRIV=) { pr(LIST@a(X)) vars L L1 L2 : List . var E : Elt.X . -- one argument reverse operation op rev1 : List -> List . eq rev1(nil) = nil . eq rev1(E | L) = rev1(L) @ (E | nil) . -- two arguments reverse operation op rev2 : List -> List . -- auxiliary function for rev2 op sr2 : List List -> List . eq rev2(L) = sr2(L,nil) . eq sr2(nil,L2) = L2 . eq sr2(E | L1,L2) = sr2(L1,E | L2) . } --> properties about LISTrev mod! PRED-LISTrev(X :: TRIV=) { pr(LISTrev(X)) -- CafeOBJ variables vars L L1 L2 L3 : List . -- rev1 distributes over _@_ reversely op rev1@ : List List -> Bool . eq rev1@(L1,L2) = (rev1(L1 @ L2) = rev1(L2) @ rev1(L1)) . -- rev1rev1 is identity function op rev1rev1 : List -> Bool . eq rev1rev1(L) = (rev1(rev1(L)) = L) . -- sr2 with _@_ op sr2@ : List List List -> Bool . eq sr2@(L1,L2,L3) = (sr2(L1,L2) @ L3 = sr2(L1,L2 @ L3)) . -- left hand of _=_ is better to be canonical -- rev1=rev2 op rev1=rev2 : List -> Bool . eq rev1=rev2(L) = (rev1(L) = rev2(L)) . } -- ========================================================== -- end end end -- ==========================================================