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

module Chapter6 where

-- The Picture example, revisited.
-- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

-- The type of pictures.

type Picture = [[Char]]

-- To flip a
-- picture in a horizontal mirror, 

flipH :: Picture -> Picture
flipH = reverse

-- and to place one picture above another it is sufficient to join the two lists of
-- lines together.

above :: Picture -> Picture -> Picture
above = (++)

-- To flip a picture in a vertical mirror.

flipV :: Picture -> Picture
flipV pic 
  = [ reverse line | line <- pic ]

-- To place two pictures side by side. 

sideBySide :: Picture -> Picture -> Picture
sideBySide picL picR
  = [ lineL ++ lineR | (lineL,lineR) <- zip picL picR ]

-- To invert the colour of a single character ...

invertChar :: Char -> Char
invertChar ch 
  = if ch=='.' then '#' else '.'

-- a line ...

invertLine :: [Char] -> [Char]
invertLine line 
  = [ invertChar ch | ch <- line ]

-- and a picture.

invertColour :: Picture -> Picture
invertColour pic 
  = [ invertLine line | line <- pic ]

-- Alternative definition of invertColour:

invertColour' :: Picture -> Picture
invertColour' pic 
  = [ [ invertChar ch | ch <- line ] | line <- pic ]


-- Extended exercise: positioned pictures
-- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

-- Positions on a plane.

type Position = (Int,Int)

-- An Image is a picture with a position.

type Image = (Picture,Position)

-- makeImage :: Picture -> Position -> Image
-- changePosition :: Image -> Position -> Image
-- moveImage :: Image -> Int -> Int -> Image
-- printImage :: Image -> IO ()


-- Local definitions
-- ^^^^^^^^^^^^^^^^^

-- The sum of the squares of two numbers.  

sumSquares :: Int -> Int -> Int

sumSquares n m 
  = sqN + sqM
    where
    sqN = n*n
    sqM = m*m

-- Add corresponding elements in two lists; lists truncated to the length of the
-- shorter one.

addPairwise :: [Int] -> [Int] -> [Int]
addPairwise intList1 intList2
  = [ m + n | (m,n) <- zip intList1 intList2 ]

-- A variant of addPairwise which doesn't truncate; see book for details of how
-- it works.

addPairwise' :: [Int] -> [Int] -> [Int]

addPairwise' intList1 intList2
  = front ++ rear
    where
    minLength = min (length intList1) (length intList2)
    front     = addPairwise (take minLength intList1) 
                            (take minLength intList2)
    rear      = drop minLength intList1 ++ drop minLength intList2

-- and a variant of this ...

addPairwise'' :: [Int] -> [Int] -> [Int]

addPairwise'' intList1 intList2
  = front ++ rear
    where
    minLength      = min (length intList1) (length intList2)
    front          = addPairwise front1 front2
    rear           = rear1 ++ rear2
    (front1,rear1) = splitAt minLength intList1
    (front2,rear2) = splitAt minLength intList2


-- Let expressions
-- ^^^^^^^^^^^^^^^

-- Two examples which use `let'.

letEx1 :: Int
letEx1 = let x = 3+2 in x^2 + 2*x - 4

letEx2 :: Int
letEx2 = let x = 3+2 ; y = 5-1 in x^2 + 2*x - y


-- Scopes
-- ^^^^^^
-- Is a value odd? even?

isOdd, isEven :: Int -> Bool

isOdd n 
  | n<=0        = False
  | otherwise   = isEven (n-1)

isEven n 
  | n<0         = False
  | n==0        = True
  | otherwise   = isOdd (n-1)


-- Extended exercise: supermarket billing
-- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

-- Types of names, prices (pence) and bar-codes.

type Name    = String
type Price   = Int
type BarCode = Int

-- The database linking names prices and bar codes.

type Database = [ (BarCode,Name,Price) ]

-- The example database we use is

codeIndex :: Database
codeIndex = [ (4719, "Fish Fingers" , 121),
              (5643, "Nappies" , 1010),
              (3814, "Orange Jelly", 56),
              (1111, "Hula Hoops", 21),
              (1112, "Hula Hoops (Giant)", 133),
              (1234, "Dry Sherry, 1lt", 540)]

-- The lists of bar codes, and of Name,Price pairs.

type TillType = [BarCode]
type BillType = [(Name,Price)]

-- The length of a line in the bill.

lineLength :: Int
lineLength = 30



