|
| 1 | +structure Contract :> CONTRACT = struct |
| 2 | + |
| 3 | +type var = string |
| 4 | +datatype exp0 = I of int |
| 5 | + | R of real |
| 6 | + | B of bool |
| 7 | + | Var of var |
| 8 | + | BinOp of string * exp0 * exp0 |
| 9 | + | UnOp of string * exp0 |
| 10 | + | Obs of string * int |
| 11 | + |
| 12 | +type 'a exp = exp0 |
| 13 | +type boolE = bool exp |
| 14 | +type 'a num = unit |
| 15 | +type intE = int num exp |
| 16 | +type realE = real num exp |
| 17 | + |
| 18 | +infix !+! !-! !*! !<! !=! !|! |
| 19 | +fun x !+! y = BinOp("+",x,y) |
| 20 | +fun x !-! y = BinOp("-",x,y) |
| 21 | +fun x !*! y = BinOp("*",x,y) |
| 22 | +fun x !<! y = BinOp("<",x,y) |
| 23 | +fun x !=! y = BinOp("=",x,y) |
| 24 | +fun x !|! y = BinOp("|",x,y) |
| 25 | +fun not x = UnOp("not",x) |
| 26 | +fun max (x,y) = BinOp("max",x,y) |
| 27 | +fun min (x,y) = BinOp("min",x,y) |
| 28 | + |
| 29 | +val obs : (string*int) -> 'a exp = Obs |
| 30 | + |
| 31 | +exception Eval of string |
| 32 | + |
| 33 | +fun binopII opr i1 i2 = |
| 34 | + case opr of |
| 35 | + "+" => I (i1+i2) |
| 36 | + | "-" => I (i1-i2) |
| 37 | + | "*" => I (i1*i2) |
| 38 | + | "<" => B (i1<i2) |
| 39 | + | "=" => B (i1=i2) |
| 40 | + | "max" => I(if i1 >= i2 then i1 else i2) |
| 41 | + | "min" => I(if i1 <= i2 then i1 else i2) |
| 42 | + | _ => raise Fail ("binopII: operator not supported: " ^ opr) |
| 43 | + |
| 44 | +fun binopRR opr r1 r2 = |
| 45 | + case opr of |
| 46 | + "+" => R (r1+r2) |
| 47 | + | "-" => R (r1-r2) |
| 48 | + | "*" => R (r1*r2) |
| 49 | + | "<" => B (r1<r2) |
| 50 | + | "=" => B (Real.compare(r1,r2) = EQUAL) |
| 51 | + | "max" => R(if r1 >= r2 then r1 else r2) |
| 52 | + | "min" => R(if r1 <= r2 then r1 else r2) |
| 53 | + | _ => raise Fail ("binopRR: operator not supported: " ^ opr) |
| 54 | + |
| 55 | +fun binopBB opr b1 b2 = |
| 56 | + case opr of |
| 57 | + "=" => B (b1=b2) |
| 58 | + | _ => raise Fail ("binopBB: operator not supported: " ^ opr) |
| 59 | + |
| 60 | +type date = Date.date |
| 61 | + |
| 62 | +type env = string*date*int -> real option (* int is a date offset *) |
| 63 | + |
| 64 | +val emptyEnv : env = fn _ => NONE |
| 65 | + |
| 66 | +fun date_eq d1 d2 = Date.compare (d1,d2) = EQUAL |
| 67 | + |
| 68 | +fun addFixing ((s,d,r),e:env) : env = |
| 69 | + fn k => |
| 70 | + let val off = #3 k |
| 71 | + in if s = #1 k andalso off >= 0 andalso date_eq d (DateUtil.addDays off (#2 k)) then SOME r |
| 72 | + else if s = #1 k andalso off < 0 andalso date_eq (DateUtil.addDays (~off) d) (#2 k) then SOME r |
| 73 | + else e k |
| 74 | + end |
| 75 | + |
| 76 | +fun eval (E:env,d:date) e = |
| 77 | + case e of |
| 78 | + Var s => raise Eval ("variable " ^ s) |
| 79 | + | I _ => e |
| 80 | + | R _ => e |
| 81 | + | B _ => e |
| 82 | + | Obs (s,off) => |
| 83 | + (case E (s,d,off) of |
| 84 | + SOME r => R r |
| 85 | + | NONE => raise Eval "unresolved observable") |
| 86 | + | BinOp(opr,e1,e2) => |
| 87 | + (case (eval (E,d) e1, eval (E,d) e2) of |
| 88 | + (I i1, I i2) => binopII opr i1 i2 |
| 89 | + | (R r1, R r2) => binopRR opr r1 r2 |
| 90 | + | (B b1, B b2) => binopBB opr b1 b2 |
| 91 | + | _ => raise Fail "eval.BinOp: difference in argument types") |
| 92 | + | UnOp("not", e1) => |
| 93 | + (case eval (E,d) e1 of |
| 94 | + B b => B(Bool.not b) |
| 95 | + | _ => raise Fail "eval.UnOp.not - wrong argument type") |
| 96 | + | UnOp(opr,_) => raise Fail ("eval.UnOp: unsupported operator: " ^ opr) |
| 97 | + |
| 98 | +fun evalR E e = |
| 99 | + case eval E e of R r => r |
| 100 | + | _ => raise Fail "evalR: expecting real" |
| 101 | +fun evalI E e = |
| 102 | + case eval E e of I i => i |
| 103 | + | _ => raise Fail "evalI: expecting real" |
| 104 | + |
| 105 | +fun evalB E e = |
| 106 | + case eval E e of B b => b |
| 107 | + | _ => raise Fail "evalB: expecting real" |
| 108 | + |
| 109 | +fun ppExp e = |
| 110 | + let fun par s = "(" ^ s ^ ")" |
| 111 | + fun notfixed opr = opr = "max" orelse opr = "min" |
| 112 | + in case e of |
| 113 | + Var s => "Var" ^ par s |
| 114 | + | I i => Int.toString i |
| 115 | + | R r => Real.toString r |
| 116 | + | B b => Bool.toString b |
| 117 | + | Obs (s,off) => "Obs" ^ par (s ^ "@" ^ Int.toString off) |
| 118 | + | BinOp(opr,e1,e2) => |
| 119 | + if notfixed opr then opr ^ par (ppExp e1 ^ "," ^ ppExp e2) |
| 120 | + else par(ppExp e1 ^ opr ^ ppExp e2) |
| 121 | + | UnOp(opr, e1) => opr ^ par (ppExp e1) |
| 122 | + end |
| 123 | + |
| 124 | +fun certainExp e = |
| 125 | + case e of |
| 126 | + Var _ => false |
| 127 | + | I _ => true |
| 128 | + | R _ => true |
| 129 | + | B _ => true |
| 130 | + | Obs _ => false |
| 131 | + | BinOp(_,e1,e2) => certainExp e1 andalso certainExp e2 |
| 132 | + | UnOp(_,e1) => certainExp e1 |
| 133 | + |
| 134 | +fun simplifyExp P e = (* memo: rewrite to bottom-up strategy to avoid the quadratic behavior *) |
| 135 | + eval P e |
| 136 | + handle Eval _ => |
| 137 | + case e of |
| 138 | + UnOp(f,e1) => UnOp(f,simplifyExp P e1) |
| 139 | + | BinOp(f,e1,e2) => BinOp(f,simplifyExp P e1,simplifyExp P e2) |
| 140 | + | _ => e |
| 141 | + |
| 142 | +open Currency |
| 143 | +type party = string |
| 144 | +datatype contr = |
| 145 | + TransfOne of cur * party * party |
| 146 | + | Scale of realE * contr |
| 147 | + | Transl of intE * contr |
| 148 | + | All of contr list |
| 149 | + | If of boolE * contr * contr |
| 150 | + | CheckWithin of boolE * intE * contr * contr |
| 151 | + (* if cond : boolE becomes true within time: intE then contract 1 in effect. |
| 152 | + otherwise (time expired, always false) contract 2 in effect |
| 153 | + *) |
| 154 | + |
| 155 | +fun ppContr c = |
| 156 | + let fun par s = "(" ^ s ^ ")" |
| 157 | + in case c of |
| 158 | + TransfOne(c,p1,p2) => "TransfOne" ^ par (ppCur c ^ "," ^ p1 ^ "," ^ p2) |
| 159 | + | Scale (e,c) => "Scale" ^ par (ppExp e ^ "," ^ ppContr c) |
| 160 | + | Transl(e,c) => "Transl" ^ par (ppExp e ^ "," ^ ppContr c) |
| 161 | + | All[] => "emp" |
| 162 | + | All cs => "All" ^ par (ppContrs cs) |
| 163 | + | If(e,c1,c2) => "If" ^ par (ppExp e ^ ", " ^ ppContr c1 ^ ", " ^ ppContr c2) |
| 164 | + | CheckWithin (e1, e2, c1, c2) => |
| 165 | + "CheckWithin" ^ par (ppExp e1 ^ ", " ^ ppExp e2 ^ ", " ^ ppContr c1 ^ ", " ^ ppContr c2) |
| 166 | + end |
| 167 | +and ppContrs [] = "" |
| 168 | + | ppContrs [c] = ppContr c |
| 169 | + | ppContrs (c::cs) = ppContr c ^ ", " ^ ppContrs cs |
| 170 | + |
| 171 | +val transfOne = TransfOne |
| 172 | +val transl = Transl |
| 173 | +val checkWithin = CheckWithin |
| 174 | +val iff = If |
| 175 | +val all = All |
| 176 | +val scale = Scale |
| 177 | + |
| 178 | +(* Shorthand notation *) |
| 179 | +fun flow(d,v,c,from,to) = scale(v,transl(d,transfOne(c,from,to))) |
| 180 | +val emp = All [] |
| 181 | + |
| 182 | +end |
0 commit comments