(* Code for lectures 7 and 8, Spring 2009 *) (* Set data abstraction, with union and intersection * mem x empty = false * mem x (add x S)=true * mem x (rem x S)=false * mem x (union S1 S2)=(mem x S1) || (mem x S2) * mem x (inter S1 S2)=(mem x S1 )&& (mem x S2) * size empty = 0 * size (add x S) = if mem x S then (size S) else (size S)+1 * size (rem x S) = if mem x S then (size S)-1 else (size S) *) module type SETSIG = sig type 'a set val empty : 'a set val add : 'a -> 'a set -> 'a set val mem : 'a -> 'a set -> bool val rem : 'a -> 'a set -> 'a set val size: 'a set -> int val union: 'a set -> 'a set -> 'a set val inter: 'a set -> 'a set -> 'a set end (* Simple implementation of sets as lists with duplicates *) module Set : SETSIG = struct type 'a set = 'a list let empty = [] let add x l = x :: l let mem x l = List.mem x l let rem x l = List.filter (fun h -> h<>x) l let rec size l = match l with [] -> 0 | h::t -> size(t) + (if List.mem h t then 0 else 1) let union l1 l2 = l1 @ l2 let inter l1 l2 = List.filter (fun h -> List.mem h l2) l1 end (* Test cases, using assertion *) let ts = Set.add 1 Set.empty;; assert (Set.mem 1 ts);; let ts = Set.add 1 ts;; assert (Set.mem 1 ts);; let ts = Set.add 2 ts;; assert ((Set.mem 1 ts) && (Set.mem 2 ts));; assert ((Set.size ts)=2);; let ts = Set.rem 1 ts;; assert ((not(Set.mem 1 ts)) && (Set.mem 2 ts));; let ts = Set.rem 2 ts;; assert (ts = Set.empty);; let ts = (Set.add 2 (Set.add 1 (Set.add 1 Set.empty)));; let ts1 = (Set.add 2 (Set.add 3 (Set.add 1 Set.empty)));; let tsi = Set.inter ts ts1;; assert((Set.mem 1 tsi) && (Set.mem 2 tsi) && (not (Set.mem 3 tsi)));; let tsi = Set.inter ts1 ts;; assert((Set.mem 1 tsi) && (Set.mem 2 tsi) && (not (Set.mem 3 tsi)));; let tsu = Set.union ts ts1;; assert((Set.mem 1 tsu) && (Set.mem 2 tsu) && (Set.mem 3 tsu));; let tsn = Set.inter Set.empty ts1;; assert(tsn = Set.empty);; let tsn = Set.inter ts1 Set.empty;; assert(tsn = Set.empty);; (* Simple implementation of sets as lists without duplicates *) module Set : SETSIG = struct type 'a set = 'a list let empty = [] let add x l = if List.mem x l then l else x :: l (* now check if already member *) let mem x l = List.mem x l let rem x l = List.filter (fun h -> h<>x) l let size l = List.length l (* now just use length *) let union l1 l2 = (* now check if already in other set *) List.fold_left (fun a x -> if List.mem x l2 then a else x::a) l2 l1 let inter l1 l2 = List.filter (fun h -> List.mem h l2) l1 end (* Simple polynomial data abstraction *) module type POLYNOMIAL = sig (* A poly is a univariate polynomial with integer * coefficients. For example, 2 + 3x + x^3. *) type poly (* zero is the polynomial 0 *) val zero: poly (* singleton(c,d) is the polynomial cx^d. * Requires: d >= 0 *) val singleton: int*int -> poly (* degree(p) is the degree of the polynomial: * the largest exponent of the polynomial with * a nonzero coefficient *) val degree: poly -> int (* evaluate(p,x) is p evaluated for the integer value x *) val evaluate: poly*int -> int (* coeff(p,n) is the coefficient c of the term * of form cx^n, or zero if there is no such term. * Requires: d >= 0 *) val coeff: poly*int -> int (* plus, minus, times are +, -, * on polynomials, * respectively *) val plus: poly * poly -> poly val minus: poly * poly -> poly val times: poly * poly -> poly (* toString converts a poly to a nicely readable string *) val toString: poly -> string end module Polynomial : POLYNOMIAL = struct (* Univariate polynomials represented using a list of coefficients. * Degree of each term is based on its position in the list. *) type poly = int list let zero = [] (* A singleton cx^d is a list of length d, where the first d-1 * elements are 0 and the last element is c *) let rec singleton(coeff, degree) = match (coeff, degree) with (0, _) -> zero | (c, 0) -> [c] | (c, d) -> if (d<0) then raise(Failure "negative degree") else 0::singleton(c, d-1) let degree(p) = match p with [] -> 0 | _ -> List.length(p)-1 let rec coeff(p, n) = match p with [] -> 0 | h::t -> if n = 0 then h else coeff(t, n-1) (* plus and minus both operate on two polynomials term by term, * so this function abstracts out the common pattern *) let rec termapply (f,p,q) = match (p,q) with ([],[]) -> [] | ([],b::q2) -> f(0,b)::termapply(f,[],q2) | (a::p2, []) -> f(a,0)::termapply(f,p2,[]) | (a::p2, b::q2) -> f(a,b)::termapply(f,p2,q2) let plus(p, q) = termapply((fun (a,b) -> a+b), p, q) let minus(p, q) = termapply((fun (a,b) -> a-b), p, q) let times(p, q) = raise(Failure "Not implemented") let evaluate (p, x) = List.fold_right (fun h a -> h+x*a) p 0 let toString (p) = let term (d,s) c = if c=0 then (d+1,s) else (d+1, (if s ="" then "" else s ^ " + ") ^ (if c=1 then "" else (if c=(-1) then "-" else string_of_int(c))) ^ (if d > 0 then "x" ^ (if d > 1 then "^" ^ string_of_int(d) else "") else "")) in match List.fold_left term (0,"") p with (d,s) -> s end let px2 = Polynomial.singleton(1,2);; let p3x2 = Polynomial.singleton(3,2);; let p2x3 = Polynomial.singleton(2,3);; let p3x4 = Polynomial.singleton(3,4);; let px5 = Polynomial.singleton(1,5);; let tp1 = Polynomial.plus(px2,px2);; let tp2 = Polynomial.plus(tp1, Polynomial.plus(p2x3,px5));; Polynomial.evaluate(tp2,2);; Polynomial.toString(tp2);;