% vim: set ts=8 et sw=4: % $Id$ % ------------------------------------------------------------------ \section{Sample} % ------------------------------------------------------------------ This module is a toy example for an MLburg specifcation and its client. The [[sample.mlb]] file specifies a simple calculator with some optimizations for addition. With the help of chain rules every number can be represented as a string and vice versa. <>= %term int string -- terminal types must be declared %type number {: int :} -- type declarations for nonterms are optional %type str {: string :} %% number : Add(x:number, y:number) [2] {: x + y :} number : Add(x:number, Add(y:number, z:number)) [2] {: x + y + z:} number : Add(x:number, Const(0)) [1] {: x :} number : Add(Const(0), Const(0)) [0] {: 0 :} number : Sub(n:number, m:number) {: n-m :} number : Mul(n:number, m:number) {: n*m :} number : Div(n:number, m:number) {: if m = 0 then assert false else n/m :} number : Const(x: int) [1] {: x :} number : Const(0) [0] {: 0 :} -- Terminal variables are bound in cost expressions str : Str(x: string) {: String.length x :} {: x :} str : Cons(x: string, y:string) [2] {: x ^ y :} -- recursive chain rules -- "number" is an abbreviation for "number:number" str : n:number [1] {: string_of_int n :} number : str [1] {: int_of_string str :} @ % ------------------------------------------------------------------ \subsection{The Client} % ------------------------------------------------------------------ The client represents expressions over numbers and strings as trees and has some code that walks over an expression. During a walk it passes the tree to generated functions to obtain a plan. Finally, it executes the plan. <>= type number = | Add of number * number | Sub of number * number | Div of number * number | Mul of number * number | Const of int | Str of str and str = | String of string | Cons of string * string | Number of number @ Constructor functions make it easier to build expressions. <>= let add x y = Add(x,y) let sub x y = Sub(x,y) let mul x y = Mul(x,y) let div x y = Div(x,y) let const x = Const(x) let str s = Str(s) let string s = String(s) let cons x y = Cons(x,y) let number x = Number(x) @ The following code traverses an expression tree bottom up and passes it to the corressponding generated functions. <>= module S = Sample let rec fold_num = function | Add(l,r) -> S.conAdd (fold_num l) (fold_num r) | Sub(l,r) -> S.conSub (fold_num l) (fold_num r) | Mul(l,r) -> S.conMul (fold_num l) (fold_num r) | Div(l,r) -> S.conDiv (fold_num l) (fold_num r) | Const(x) -> S.conConst x | Str(s) -> fold_str s and fold_str = function | String(x) -> S.conStr x | Cons(x,y) -> S.conCons x y | Number(n) -> fold_num n @ Here are come expressions to play with. <>= let exp0 = (* costs: number: 5, str: 6 *) add (const 0) (add (const 3) (const 7)) let exp1 = (* costs: number: 10, str: 11 *) add (add (str (string "123")) (str (number (const 8)))) (add (const 7) (const 0)) let number_cost exp = (fold_num exp).S.number.Camlburg.cost let str_cost exp = (fold_num exp).S.str.Camlburg.cost let to_number exp = (fold_num exp).S.number.Camlburg.action () let to_string exp = (fold_num exp).S.str.Camlburg.action () @