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

module Chapter12 where

-- Overloading and type classes
-- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

-- Why overloading?
-- ^^^^^^^^^^^^^^^^

-- Testing for membership of a Boolean list.

elemBool :: Bool -> [Bool] -> Bool

elemBool x [] = False
elemBool x (y:ys)
  = (x == y) || elemBool x ys

-- Testing for membership of a general list, with the equality function as a
-- parameter.

elemGen :: (a -> a -> Bool) -> a -> [a] -> Bool

elemGen eqFun x [] = False
elemGen eqFun x (y:ys)
  = (eqFun x y) || elemGen eqFun x ys


-- Introducing classes
-- ^^^^^^^^^^^^^^^^^^^

-- Definitions of classes cannot be hidden, so the definitions etc. here are not
-- executable.

-- class Eq a where
--   (==) :: a -> a -> Bool

-- Functions which use equality
-- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

-- Testing for three values equal: more general than Int -> Int -> Int -> Bool.

allEqual :: Eq a => a -> a -> a -> Bool
allEqual m n p = (m==n) && (n==p)

-- elem :: Eq a => a -> [a] -> Bool
-- books :: Eq a => [ (a,b) ] -> a -> [b]

-- It is easier to see this typing if you remane books lookupFirst:

lookupFirst :: Eq a => [ (a,b) ] -> a -> [b]

lookupFirst ws x 
  = [ z | (y,z) <- ws , y==x ]

-- borrowed    :: Eq b => [ (a,b) ] -> b -> Bool
-- numBorrowed :: Eq a => [ (a,b) ] -> a -> Int


-- Signatures and Instances
-- ^^^^^^^^^^^^^^^^^^^^^^^^

-- The Visible class:

class Visible a where
  toString :: a -> String
  size     :: a -> Int

-- A type is made a member or instance of a class by defining
-- the signature functions for the type. For example,

-- instance Eq Bool where
--   True  == True  = True
--   False == False = True
--   _     == _     = False

-- Declaring examples of the Visible class

instance Visible Char where
  toString ch  = [ch]
  size _       = 1

instance Visible Bool where
  toString True  = "True"
  toString False = "False"
  size _         = 1

-- An instance declaration with a context.

instance Visible a => Visible [a] where
  toString = concat . map toString  
  size     = foldr (+) 1 . map size  


-- Default definitions
-- ^^^^^^^^^^^^^^^^^^^

-- To return to our example of equality, the Haskell equality class is in fact
-- defined by

-- class Eq a where
--   (==), (/=) :: a -> a -> Bool
--   x /= y     = not (x==y)
--   x == y     = not (x/=y)


-- Derived classes
-- ^^^^^^^^^^^^^^^

-- Ordering is built on Eq.

-- class Eq a => Ord a where
--   (<), (<=), (>), (>=) :: a -> a -> Bool
--   max, min             :: a -> a -> a
--   compare              :: a -> a -> Ordering


-- This is the same definition as in Chapter7, but now with an overloaded type.

iSort :: Ord a => [a] -> [a]

iSort []	= []
iSort (x:xs) = ins x (iSort xs)

-- To insert an element at the right place into a sorted list.

ins :: Ord a => a -> [a] -> [a]

ins x []    = [x]
ins x (y:ys)
  | x <= y	= x:(y:ys)
  | otherwise	= y : ins x ys


-- Multiple constraints
-- ^^^^^^^^^^^^^^^^^^^^

-- Sorting visible objects ...

vSort :: (Ord a,Visible a) => [a] -> String

vSort = toString . iSort 

-- Similarly, 

vLookupFirst :: (Eq a,Visible b) => [(a,b)] -> a -> String

vLookupFirst xs x = toString (lookupFirst xs x)

-- Multiple constraints can occur in an instance declaration, such as

-- instance (Eq a,Eq b) => Eq (a,b) where
--   (x,y) == (z,w)  =  x==z && y==w

-- Multiple constraints can also occur in the definition of a class,

class (Ord a,Visible a) => OrdVis a

-- Can then give vSort the type:

-- 	vSort :: OrdVis a => [a] -> String

-- A tour of the built-in Haskell classes
-- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

-- For details of the code here, please see the standard Prelude and Libraries.


-- Types and Classes
-- ^^^^^^^^^^^^^^^^^

-- The code in this section is not legal Haskell.

-- To evaluate the type of concat . map show, type

-- 	:type concat . map show

-- to the Hugs prompt.

