-- | Working with List
-- Examples to illustrate pattern matching, recursion and testing for lists
-- Functional Programming course 2016.
-- Thomas Hallgren
{-
This started out as a skeleton, the definitions were filled in
during the lecture.
-}
import Prelude hiding ((++),reverse,take,drop,splitAt,zip,unzip)
import qualified Prelude
import Test.QuickCheck
(++) :: [a] -> [a] -> [a]
[] ++ ys = ys
xs ++ [] = xs
(x:xs) ++ ys = x:(xs++ys)
cons x xs = x:xs
snoc xs x = xs++[x]
reverse :: [a] -> [a]
reverse [] = []
reverse (x:xs) = reverse xs ++ [x]
-- complexity? how to make it more efficient?
-- | Take the first n elements of a list
take :: Int -> [a] -> [a]
take n _ | n<=0 = []
take _ [] = []
take n (x:xs) = x:take (n-1) xs
prop_take n xs = length (take n xs) == max 0 (min n (length xs))
-- | Discard the first n elements of a list
drop :: Int -> [a] -> [a]
drop n xs| n<=0 = xs
drop _ [] = []
drop n (x:xs) = drop (n-1) xs
prop_take_drop n xs = take n xs ++ drop n xs == (xs::[Int])
nonprop_take_drop n xs = drop n xs ++ take n xs == (xs::[Int])
-- | 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 (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 [] = ([],[])
unzip ((x,y):xys) = let (xs,ys) = unzip xys in (x:xs,y:ys)
prop_zip_unzip :: (Eq a,Num a) => [(a,a)] -> Bool
prop_zip_unzip xys = let (xs,ys) = unzip xys in zip xs ys == xys
prop_unzip_zip xs ys = unzip (zip xs ys) == (xs,ys)
-- | "Quicksort"
qsort :: Ord a => [a] -> [a]
qsort [] = []
qsort (x:xs) = qsort [y|y<-xs,y=x]
-- * Filled in after the lecture
-- | insert a new element at the right position in a sorted list
insert :: Ord a => a -> [a] -> [a]
insert x [] = [x]
insert x (x1:xs) | x [a] -> [a]
isort [] = []
isort (x:xs) = insert x (isort xs)
prop_qsort xs = qsort xs == isort (xs::[Int])