module L02A where import Test.QuickCheck -- Datatypes -- David Sands -- 2018-09-07 -- Continued 2017-09-11 -- Example of a datatype definition: -- data Bool = True | False -- Colour data Colour = Red | Black deriving (Eq,Show) -- The Suit (Another example of an enumeration type) data Suit = Hearts | Diamonds | Clubs | Spades deriving (Eq,Show) colour :: Suit -> Colour {- colour s | s == Hearts = Red | s == Diamonds = Red | otherwise = Black -} -- Preferable to use Pattern matching: colour Hearts = Red colour Diamonds = Red colour _ = Black -- Rank: a datatype for the rank of a card data Rank = Numeric Int | Jack | Queen | King | Ace deriving (Eq,Show) -- Datatype invariant prop_Rank :: Rank -> Bool prop_Rank (Numeric n) = n > 1 && n < 11 prop_Rank _ = True -- Card: a data type containing a Rank and a Suit -- and its projection functions data Card = Card Rank Suit | Joker deriving (Eq,Show) -- projection functions rank :: Card -> Rank suit :: Card -> Suit rank :: Card -> Rank rank (Card r _) = r suit :: Card -> Suit suit (Card _ s) = s type Hand = [Card] -------- Lecture ended here 2018---------- -- example card oneEye :: Card oneEye = Card King Diamonds -- Example: Q: what if you wanted to print a card more nicely showCard :: Card -> String showCard (Card r s) = showRank r ++ " of " ++ show s where showRank (Numeric n) = show n showRank r = show r -- Hand type -- and shorthand form defining all three -- data Card = Card {rank::Rank, suit::Suit} -- Really useful when there are lots of things e.g. -- data Person = Person [String] String Int Int Int Int -- ... -- data Person = Person [Name] Name Year Month Day Pnr type Name = String type Year = Int type Month = Int type Day = Int type Pnr = Int -- year :: Person -> Year -- year (Person _ _ y _ _ _) = y data Person = Person{ firstnames :: [Name] , familyname :: Name , year :: Year , month :: Month , day :: Day , pnr :: Pnr } deriving Show turing = Person ["Alan", "Mathison"] "Turing" 1912 6 23 0 -- cardBeats card1 card2 checks if card1 beats card2 -- w & wo pattern matching -- cardBeats :: Card -> Card -> Bool -- rank1 `rankBeats` rank2 ? -- when is one rank higher than another? -- "longhand" definition in the slides. rankBeats :: Rank -> Rank -> Bool rankBeats _ Ace = False rankBeats Ace _ = True rankBeats _ King = False rankBeats King _ = True rankBeats _ Queen = False rankBeats Queen _ = True rankBeats _ Jack = False rankBeats Jack _ = True rankBeats (Numeric m) (Numeric n) = m > n prop_rankBeats r1 r2 = r1 `rankBeats` r2 || r2 `rankBeats` r1 || r1==r2 -- Exercise: a better property: exactly one of these three alternatives is True -- Example (if there is time) -- If we wanted to include Jokers how should we modify the datatype? ----------------------------------------------- ------------------------------------------------------- -- The quickCheck "magic" we need to get it to generate arbitrary -- elements of our new datatypes: instance Arbitrary Suit where arbitrary = elements [Spades, Hearts, Diamonds, Clubs] instance Arbitrary Rank where arbitrary = oneof $ [ do return c | c <- [Jack,Queen,King,Ace] ] ++ [ do n <- choose (2,10) return (Numeric n) ] {- instance Arbitrary Card where arbitrary = do r <- arbitrary s <- arbitrary return (Card r s) -} -------------------------------------------------------------------------