(* CS:3820, Fall 2018 *) (* Cesare Tinelli *) (* The University of Iowa *) (* F# examples seen in class *) (* Algebraic data types *) (* aka Discriminated Unions *) type mood = Happy | Sad | Mad let m = Happy let f = function Happy -> "\n:-)\n" | Sad -> "\n:-(\n" | _ -> "\n:-@\n" System.Console.WriteLine (f Happy) System.Console.WriteLine (f Sad) System.Console.WriteLine (f Mad) type btree = | Empty | Node of (btree * int * btree) Empty let e = Empty let t3 = Node(e,3,e) let t5 = Node (e, 5, e) let t9 = Node (t3,9,t5) let t4 = Node(t9,4,e) t4 (* t4 corresponds to this tree: (4) / \ (9) () / \ / \ (3) (5) / \ / \ () () () () *) let newTree n = Node(Empty, n, Empty) newTree 10 // Extracts value of root node if t is a non-empty tree let rootValue t = match t with Node (_, v, _) -> v | _ -> failwith "Empty tree" t3 rootValue t3 rootValue e // Extracts left subtree if t is non-empty let leftChild t = match t with Node (t, _, _) -> t | _ -> failwith "Empty tree" t3 leftChild t3 t9 leftChild t9 // Extracts right subtree if t is non-empty let rightChild t = match t with Node (_, _, t) -> t | _ -> failwith "Empty tree" // returns true iff integer n occurs in tree t let rec occurs n t = match t with Empty -> false | Node (t1, m, t2) -> (m = n) || (occurs n t1) || (occurs n t2) t4 occurs 10 t4 occurs 9 t4 // "inserts" integer n in tree t so that // all nodes to the left have a smaller or equal value let rec insert n t = match t with Empty -> newTree n | Node (t1, m, t2) -> if (n < m) then Node (insert n t1, m, t2) else Node (t1, m, insert n t2) let s = Node (Empty, 3, Node (Empty, 6, Empty)) (* (3) / \ () (6) / \ () () *) let s1 = insert 4 s (* (3) / \ () (6) / \ (4) () / \ () () *) let s2 = insert 5 s1 (* (3) / \ () (6) / \ (4) () / \ () (5) / \ () () *) // collects all integer values in tree t into a list let rec traverse t = match t with Empty -> [] | Node (t1, m, t2) -> let l1 = traverse t1 in let l2 = traverse t2 in l1 @ [m] @ l2 traverse s2 (* From Chap 1 of the Sestoft *) (* Every programming language has a - a _concrete syntax, i.e., a textual representation for its programs – an _abstract syntax_, a tree-like representation for its programs *) (* Representing abstract syntax using recursive datatypes *) type expr = | CstI of int | Prim of string * expr * expr // Values of type can be used as abstract syntax version // of the usual arithmetic expressions over the integers let e1 = CstI 17 (* Represents constant expression: 17 *) let e2 = Prim("-", CstI 3, CstI 4) (* - / \ 3 4 Structured representation of the expression: 3 - 4 The value of e2 is an _abstract syntax tree_ of (3 - 4) *) let e3 = Prim("+", Prim("*", CstI 2, CstI 9), CstI 10) (* + / \ * 10 / \ 2 9 Abstract syntax tree of: (2 * 9) + 10 *) let e4 = Prim("*", CstI 2, Prim("+", CstI 9, CstI 10)) (* * / \ 2 + / \ 9 10 Abstract syntax tree of: 2 * (9 + 10) *) let e5 = Prim("+", Prim("*", CstI 7, CstI 9), Prim("/", CstI 2, CstI 10)) (* + / \ / \ * * / \ / \ 7 9 2 10 Abstract syntax tree of: 3*9 + 2*10 *) (* Evaluating expressions using recursive functions *) let rec eval (e : expr) : int = match e with | CstI i -> i | Prim("+", e1, e2) -> eval e1 + eval e2 | Prim("*", e1, e2) -> eval e1 * eval e2 | Prim("-", e1, e2) -> eval e1 - eval e2 | Prim _ -> failwith "unknown primitive" // The eval function is an interpreter for _programs_ in the expr language // The meaning of the operators is defined by eval (in terms of F# operators) // 17 let v1 = eval e1 // 3 - 4 let v2 = eval e2 // (2 * 9) + 10 let v3 = eval e3 // 2 * (9 + 10) let v4 = eval e4 (* Changing the meaning of subtraction *) let rec eval2 (e : expr) : int = match e with | CstI i -> i | Prim("+", e1, e2) -> eval2 e1 + eval2 e2 | Prim("*", e1, e2) -> eval2 e1 * eval2 e2 | Prim("-", e1, e2) -> let res = eval2 e1 - eval2 e2 in if res < 0 then 0 else res | Prim _ -> failwith "unknown primitive" // eval2 interprets - as cut-off subtraction, whose result is never negative // This yieds a _new_ language even if the abstract syntax is the same let e4v = eval2 (Prim("-", CstI 10, CstI 27))