---------------------------------------------------------------------
-- 	Haskell: The Craft of Functional Programming
-- 	Simon Thompson
-- 	(c) Addison-Wesley, 1999.
-- 
-- 	Chapter 8
---------------------------------------------------------------------

-- Reasoning about programs
-- ^^^^^^^^^^^^^^^^^^^^^^^^

module Chapter8 where

import Prelude hiding (sum,length,(++),reverse,unzip)


-- Testing and verification
-- ^^^^^^^^^^^^^^^^^^^^^^^^
-- A function supposed to give the maximum of three (integer) values.

mysteryMax :: Int -> Int -> Int -> Int
mysteryMax x y z
  | x > y && x > z      = x
  | y > x && y > z      = y
  | otherwise           = z

-- Definedness and termination
-- ^^^^^^^^^^^^^^^^^^^^^^^^^^^

-- A factorial function, giving an undefined result on negative integers.

fact :: Int -> Int
fact n
  | n==0        = 1
  | otherwise   = n * fact (n-1)

-- An infinite list

posInts :: [Int]
posInts = [1, 2 .. ]


-- Induction
-- ^^^^^^^^^

-- The sum function, defined recursively.

sum :: [Int] -> Int

sum []     = 0					-- (sum.1)
sum (x:xs) = x + sum xs				-- (sum.2)

-- Double every element of an integer list.

doubleAll :: [Int] -> [Int]

doubleAll []     = []				-- (doubleAll.1)
doubleAll (z:zs) = 2*z : doubleAll zs		-- (doubleAll.2)

-- The property linking the two:
-- 	sum (doubleAll xs) = 2 * sum xs			-- (sum+dblAll)


-- Other functions used in the examples
-- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

-- The definitions given here use explicit recursion, rather than applying 
-- higher-order functions as may happen in the Prelude definitions.

length :: [a] -> Int

length []     = 0				-- (length.1)
length (z:zs) = 1 + length zs			-- (length.2)
 
(++) :: [a] -> [a] -> [a]

[]     ++ zs = zs				-- (++.1)
(w:ws) ++ zs = w:(ws++zs)			-- (++.2)

reverse :: [a] -> [a]

reverse []     = []				-- (reverse.1)
reverse (z:zs) = reverse zs ++ [z]		-- (reverse.2)

unzip :: [(a,b)] -> ([a],[b])

unzip [] = ([],[])
unzip ((x,y):ps) 
  = (x:xs,y:ys)
    where
    (xs,ys) = unzip ps                   


-- Generalizing the proof goal
-- ^^^^^^^^^^^^^^^^^^^^^^^^^^^

-- The shunting function

shunt :: [a] -> [a] -> [a]

shunt []     ys = ys				-- (shunt.1)
shunt (x:xs) ys = shunt xs (x:ys) 		-- (shunt.2)

rev :: [a] -> [a]

rev xs = shunt xs []				-- (rev.1)

-- An alternative definition of the factorial function.

fac2 :: Int -> Int

fac2 n = facAux n 1

facAux :: Int -> Int -> Int

facAux 0 p = p
facAux n p = facAux (n-1) (n*p)

