-------------------------------------------------------------------- {- 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 -} -------------------------------------------------------------------- -- summan xs 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: do a ":i Num" in Hugs and see. -} --------------------------------------------------------------------