import Test.QuickCheck -------------------------------------------------------------------- {- We have seen the datatype for Hand (cardplay): data Hand = Empty | Add Card Hand This seems to be a nice solution, that could be of general interest. In general, when modelling a "collection" of things, we could use the same principle. Let us try to define a datatype for lists: data List = Empty | Add ? List So, a list is either: * Empty * or it has at least one element (the first), and we model the rest of the elements with a list again What should be on the place of the ? question mark? Answer: this should be decided by the persion who uses this type, so we turn this into a parameter. -} -------------------------------------------------------------------- -- a datatype for lists data List a = Empty | Add a (List a) deriving ( Show, Eq ) {- -- we can now model a Hand by using a List type Hand = List Card -} -- tom list checks whether list is empty tom :: List a -> Bool tom Empty = True tom (Add x list) = False {- The type of 'tom', namely tom :: List a -> Bool means that it works for ANY type a. Note the difference between type names starting with a capital: Integer, Bool, Float, List, etc. which denote specific types, and type names with a small letter: a, b, c, etc. which denote any type. -} -- forst list returns the first element of the list forst :: List a -> a forst (Add x list) = x {- The type of 'forst', namely forst :: List a -> a means that it works for ANY type a. Note that the element type and the result type should match; they should both be 'a'. -} {- -- alternatively, we can generate an error when the list is empty: forst :: List a -> a forst Empty = error "the list is empty" forst (Add x list) = x -} -- Note: What is the type of 'error'? -- sist list returns the last element of the list sist :: List a -> a sist Empty = error "the list is empty" sist (Add x Empty) = x sist (Add x list) = sist list -- here, we know that list is non-empty -------------------------------------------------------------------- {- There is standard notation in Haskell for the above datatype and functions. [] is used for the empty list ('Empty' above) [1,2,3,4,2] is a list with 5 elements [3] is a list with one element x : list is a list with first element x, and list as the rest ('Add x list' above) [Integer] is the type of lists of Integers ('List Integer' above) -} {- -- using the Haskell built-in standard lists and notation, the above -- examples become: -- tom xs checks whether list xs is empty tom :: [a] -> Bool tom [] = True tom (x:xs) = False -- forst xs returns the first element of the list xs forst :: List a -> a forst [] = error "the list is empty" forst (x:xs) = x -- sist xs returns the last element of the list xs sist :: List a -> a sist [] = error "the list is empty" sist [x] = x sist (x:xs) = sist xs -} {- -- alternatively: sist :: List a -> a sist [] = error "the list is empty" sist (x:[]) = x sist (x:xs) = sist xs -} -------------------------------------------------------------------- -- size l (a.k.a length) returns the number of elements in l size :: [a] -> Int size [] = 0 size (x:xs) = 1 + size xs -- summan xs (a.k.a sum) calculates the sum of all elements in xs summan :: Num a => [a] -> a summan [] = 0 summan (x:xs) = x + summan xs {- The type of 'summan', namely summan :: Num a => [a] -> a means that it works for ANY type a, as long as type is a "numeric" or "Num" type. This means that it works for any type for which we have the normal arithmetic operations +, -, *, etc. Note: type ":i Num" in GHCi and see. -} -- mest l (a.k.a. maximum) returns the largest element in l mest :: Ord a => [a] -> a mest [x] = x mest (x:xs) = max x (mest xs) -------------------------------------------------------------------- -- l1 +++ l2 (a.k.a. ++) appends l2 after l1 (+++) :: [a] -> [a] -> [a] [] +++ ys = ys (x:xs) +++ ys = x : (xs +++ ys) -- rev (a.k.a. reverse) reverses the elements in l rev :: [a] -> [a] rev [] = [] rev (x:xs) = rev xs +++ [x] -- value s returns the number represented by the string s as an integer value :: String -> Integer value s = calculate (reverse s) -- Helper function for value calculate :: String -> Integer calculate "" = 0 calculate (c:s) = read [c] + 10 * calculate s -- [c] makes a 1-character string from the character c prop_Value n = n >= 0 ==> value (show n) == n --------------------------------------------------------------------