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