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
--------------------------------------------------------------------