-- | Working with List -- Examples to illustrate pattern matching, recursion and testing for lists -- Functional Programming course 2018. -- Thomas Hallgren {- This started as a skeleton, the definitions were filled in during the lecture. -} import Prelude hiding ((++),null,reverse,take,drop,splitAt,zip,unzip) import qualified Prelude import Test.QuickCheck null :: [a] -> Bool null [] = True null _ = False (++) :: [a] -> [a] -> [a] [] ++ ys = ys (x:xs) ++ ys = x : (xs ++ ys) cons x xs = x:xs snoc :: [a] -> a -> [a] snoc xs x = xs++[x] reverse :: [a] -> [a] reverse [] = [] reverse (x:xs) = reverse xs ++ [x] -- Inefficient! We will return to this in a later lecture. -- complexity? how to make it more efficient? -- | Take the first n elements of a list take :: Int -> [a] -> [a] take n xs | n<=0 = [] take n [] = [] take n (x:xs) = x:take (n-1) xs prop_take n xs = n>=0 ==> length (take n xs) == min n (length xs) -- | Discard the first n elements of a list drop :: Int -> [a] -> [a] drop n xs | n<=0 = xs drop n [] = [] drop n (_:xs) = drop (n-1) xs prop_take_drop :: Int -> [Bool] -> Property prop_take_drop n xs = classify (n<=0 || n>length xs) "extreme" (take n xs ++ drop n xs == xs) nonprop_take_drop :: Int -> [Bool] -> Bool nonprop_take_drop n xs = drop n xs ++ take n xs == xs -- | splitAt n xs = (take n xs,drop n xs) --splitAt :: Int -> [a] -> ([a],[a]) -- | Combine a pair of list into a list of pairs zip :: [a] -> [b] -> [(a,b)] --zip [] [] = [] --zip (x:xs) [] = [] --zip [] (y:ys) = [] --zip (x:xs) (y:ys) = (x,y):zip xs ys zip (x:xs) (y:ys) = (x,y):zip xs ys zip _ _ = [] -- | Split a list of pairs into a pair of lists unzip :: [(a,b)] -> ([a],[b]) --unzip xys = ([x|(x,y)<-xys], [y|(x,y)<-xys]) unzip [] = ([],[]) unzip ((x,y):xys) = (x:xs,y:ys) where (xs,ys) = unzip xys prop_zip_unzip :: [(Bool,Int)] -> Bool prop_zip_unzip xys = zip xs ys == xys where (xs,ys) = unzip xys prop_unzip_zip :: [Bool] -> [Int] -> Bool prop_unzip_zip xs ys = unzip (zip xs ys) == (take n xs,take n ys) where n = min (length xs) (length ys) -- | "Quicksort" qsort :: Ord a => [a] -> [a] qsort [] = [] qsort (x:xs) = qsort smaller ++ [x] ++ qsort bigger where smaller = [x'|x'<-xs,x'<=x] bigger = [x'|x'<-xs,x'>x] -- | insert a new element at the right position in a sorted list insert :: Ord a => a -> [a] -> [a] insert x [] = [x] insert x (x':xs) | x<=x' = x:x':xs | otherwise = x':insert x xs isSorted [] = True isSorted [x] = True isSorted (x1:x2:xs) = x1<=x2 && isSorted (x2:xs) prop_insert :: Int -> [Int] -> Property prop_insert x xs = isSorted xs ==> isSorted (insert x xs) -- QuickCheck said "Gave up! Passed only 73 tests.". We will return to this. -- in a later lecture. -- | Insertion sort (sort a list by using insert) isort :: Ord a => [a] -> [a] isort [] = [] isort (x:xs) = insert x (isort xs) prop_qsort :: [Int] -> Bool prop_qsort xs = qsort xs == isort xs