(* Code for Lecture 3: Datatypes *) (************************************************************************) Control.Print.printDepth := 100; (* Force SML to print entire datatype values, instead of replacing subexpressions with "#" (if you're using an old version of SML, this might be called Compiler.Control.Print.printDepth *) (* Type Bindings (declarations) *) type coord = real * real (* Declares a new name (coord) for the type real*real *) type complex = real * real (* Could represent complex numbers too: a + bi represented by (a, b). But this invites confusion of `coord' and `complex'. (See below for how to fix it...) *) (* Datatypes (non-recursive) *) (* suit of cards *) datatype suit = Clubs | Diamonds | Hearts | Spades (* val dom : suit * suit -> bool dom(s1,s2) = true iff suit s1 beats or is equal to suit s2 relative to the ordering S > H > D > C Invariant: none Effects: none *) fun dom (Spades, _) = true | dom (Hearts, Diamonds) = true | dom (Hearts, Clubs) = true | dom (Diamonds, Clubs) = true | dom (s1, s2) = (s1 = s2); (* rank of cards *) datatype rank = Two | Three | Four | Five | Six | Seven | Eight | Nine | Ten | Jack | Queen | King | Ace; (* A card is a rank and a suit *) type card = rank * suit (* Datatype (recursive!) *) (* A hand is either empty or it consists of a card, followed by the rest of the hand *) datatype hand = Empty | Hand of card * hand; (* Some sample hands: *) val hand0:hand = Empty; val hand1 = Hand((Ace, Hearts), Empty); val hand2 = Hand((Queen, Diamonds), hand1); val hand5 = Hand((Ace, Spades), Hand((Ten, Diamonds), Hand((Seven, Clubs), Hand((Queen, Spades), Hand((Eight, Clubs), Empty))))); (* val extract : suit * hand -> hand extract(s, h) returns a hand consisting of all cards in h of suit s. Invariant: none Effects: none *) fun extract (s:suit, Empty:hand) : hand = Empty | extract (s, Hand((r', s'), h')) = if s = s' then Hand((r',s'), extract(s, h')) else extract(s, h'); (* extract all spades from hand5 *) val spades5 = extract(Spades, hand5); (* val count: hand -> int count(h) counts the number of cards in a hand h *) fun count (Empty) = 0 | count (Hand(c, h)) = count(h) + 1 (* Returning to complex numbers: *) datatype complex = Complex of real * real (* Now we can't possibly confuse `complex' with `coord'. Downside: you have to write Complex(a,b) instead of (a,b), and pattern-match on Complex(a,b) in functions. I think this is worth it, though, to avoid nasty bugs. (A fairly similar error has caused some very expensive spacecraft to crash!) *) (* Adding and multiplying with the `complex' datatype: *) fun complexAdd (Complex(a,b), Complex(c,d)) = Complex(a + c, b + d) (* a+bi + c+di = (a + c) + (b + d)i *) fun complexMul (Complex(a,b), Complex(c,d)) = Complex(a*c - b*d, b*c + a*d) (* a+bi + c+di = (ac - bd) + (bc + ad)i *) (* Exercises: - What are the types of complexAdd and complexMul? (Take a guess, then type the code into SML if you like.) - How would you write complexSub to subtract `complex'es? *)