WorkingWithLists.hs

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

Plain-text version of WorkingWithLists.hs | Valid HTML?