module Exercises05
where

{- This are approximately the live code examples developed in the CSci
   450 and 503 classes on 17 September 2014 by H. Conrad Cunningham.
-}

-- Exercise 6(a) 

hailstone :: Int -> Int
hailstone 1           = 1
hailstone n
    | n > 1 && even n = hailstone (n `div` 2)
    | n > 1           = hailstone (3*n + 1)
    | otherwise       = error ("hailstone not defined for " ++ show n)

-- Exercise 6(b)

-- using list comprehension
haillist :: [Int] -> [Int]
haillist xs = [ hailstone x | x <- xs, x > 0]

-- using map and filter
haillist' :: [Int] -> [Int]
haillist' xs = map hailstone (filter (>0) xs) -- (>0) operator section

-- directly coding map and filter patterns 
haillist'' :: [Int] -> [Int]
haillist'' []   = []
haillist'' (x:xs)
    | x > 0     = hailstone x : haillist'' xs
    | otherwise = haillist'' xs

-- Exercise 6(c) 

hailpath :: Int -> [Int]
hailpath 1           = [1]
hailpath n
    | n > 1 && even n = n : hailpath (n `div` 2)
    | n > 1           = n : hailpath (3*n + 1)
    | otherwise       = error ("hailpath not defined for " ++ show n)

-- Exercise 8

-- assuming lists are increasing
merge :: [Int] -> [Int] -> [Int]
merge [] ys     = ys
merge xs []     = xs
merge xs@(x:xs') ys@(y:ys')
    | x < y     = x:merge xs' ys
    | x > y     = y:merge xs ys'
    | otherwise = x:merge xs' ys' -- no duplicates

-- polymorphic, assumimg lists are increasing
merge' :: Ord a => [a] -> [a] -> [a]
merge' [] ys     = ys
merge' xs []     = xs
merge' xs@(x:xs') ys@(y:ys')
    | x < y     = x:merge' xs' ys
    | x > y     = y:merge' xs ys'
    | otherwise = x:merge' xs' ys' -- no duplicates

-- check increasing list
increasing :: Ord a => [a] -> Bool
increasing (x:xs@(y:ys))
    | x < y     = increasing xs
    | otherwise = False
increasing _    = True

-- check precondition on merge
merge'' :: Ord a => [a] -> [a] -> [a]
merge'' xs ys 
    | ixs && iys         = merge' xs ys
    | not ixs && not iys = error "neither argument of merge'' increasing"
    | not ixs            = error "first argument of merge'' not increasing"
    | otherwise          = error "second argument of merge'' not increasing"
        where ixs = increasing xs
              iys = increasing ys
