packages feed

Craft3e 0.2.0.4 → 0.2.0.5

raw patch · 31 files changed

+3721/−1417 lines, 31 filesdep +randomPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: random

API changes (from Hackage documentation)

- Chapter18: Nil :: Tree a
- Chapter18: Node :: a -> Tree a -> Tree a -> Tree a
- Chapter18: State :: (Table a -> (Table a, b)) -> State a b
- Chapter18: addOneInt :: IO ()
- Chapter18: addOneInt' :: IO ()
- Chapter18: data State a b
- Chapter18: data Tree a
- Chapter18: egTree :: Tree String
- Chapter18: identity :: Identity a -> a
- Chapter18: instance GHC.Base.Applicative (Chapter18.State a)
- Chapter18: instance GHC.Base.Functor (Chapter18.State a)
- Chapter18: instance GHC.Base.Monad (Chapter18.State a)
- Chapter18: instance GHC.Classes.Eq a => GHC.Classes.Eq (Chapter18.Tree a)
- Chapter18: instance GHC.Classes.Ord a => GHC.Classes.Ord (Chapter18.Tree a)
- Chapter18: instance GHC.Show.Show a => GHC.Show.Show (Chapter18.Tree a)
- Chapter18: lookup :: Eq a => a -> Table a -> Integer
- Chapter18: nNode :: Eq a => a -> Table a -> (Table a, Integer)
- Chapter18: numTree :: Eq a => Tree a -> Tree Integer
- Chapter18: numberNode :: Eq a => a -> State a Integer
- Chapter18: numberTree :: Eq a => Tree a -> State a (Tree Integer)
- Chapter18: runST :: State a b -> b
- Chapter18: sTree :: Tree Integer -> Integer
- Chapter18: sTree' :: Tree Integer -> Integer
- Chapter18: sumTree :: Tree Integer -> Identity Integer
- Chapter18: type Table a = [a]
- Chapter20: aFac :: Integer -> Integer -> Integer
- Chapter20: exam1 :: (Num a, Enum a) => a -> [a]
- Chapter20: exam2 :: (Num a, Enum a) => a -> [a]
- Chapter20: exam3 :: (Num a, Enum a) => a -> [a]
- Chapter20: exam4 :: (Num a, Enum a) => a -> [a]
- Chapter20: fac :: Integer -> Integer
- Chapter20: facFold :: (Num b, Enum b) => b -> b
- Chapter20: fib :: Integer -> Integer
- Chapter20: fibP :: Integer -> (Integer, Integer)
- Chapter20: fibs :: [Integer]
- Chapter20: foldEx1 :: (Eq a, Num a, Enum a) => a -> Bool
- Chapter20: iSort :: Ord a => [a] -> [a]
- Chapter20: ins :: Ord a => a -> [a] -> [a]
- Chapter20: mLen :: Eq a => [a] -> [a] -> Integer
- Chapter20: mSort :: Ord a => [a] -> [a]
- Chapter20: map :: Foldable t => (a -> b) -> t a -> [b]
- Chapter20: maxLen :: Eq a => [a] -> [a] -> Int -> Int -> Int
- Chapter20: maxTab :: Eq a => [a] -> [a] -> [[Int]]
- Chapter20: mer :: Ord a => [a] -> [a] -> [a]
- Chapter20: mult :: (Eq t, Num t, Num a) => a -> t -> a
- Chapter20: newFac :: Integer -> Integer
- Chapter20: qSort :: Ord a => [a] -> [a]
- Chapter20: rev1 :: [a] -> [a]
- Chapter20: rev2 :: [a] -> [a]
- Chapter20: russ :: forall {t} {a}. (Num a, Integral t) => a -> t -> a
- Chapter20: shunt :: [a] -> [a] -> [a]
- Chapter20: sq :: Num a => a -> a
- Chapter20: sumList :: [Integer] -> Integer
- Chapter20: sumSquares :: Integer -> Integer
- Test: (^^^) :: Integer -> Integer -> Integer
- Test: double :: Integer -> Integer
- Test: ex :: Integer
- Test: fac :: Integer -> Integer
- Test: fib :: Integer -> Integer
- Test: fibP :: Integer -> (Integer, Integer)
- Test: howManyEqual :: Integer -> Integer -> Integer -> Integer
- Test: maxThreeOccurs :: Integer -> Integer -> Integer -> (Integer, Integer)
- Test: pic1 :: Picture
- Test: pic2 :: Picture
- Test: pow :: Integer -> Integer
- Test: sumFun :: (Integer -> Integer) -> Integer -> Integer
- Test: trip :: Integer -> Integer
+ Chapter19: Nil :: Tree a
+ Chapter19: Node :: a -> Tree a -> Tree a -> Tree a
+ Chapter19: State :: (Table a -> (Table a, b)) -> State a b
+ Chapter19: addOneInt :: IO ()
+ Chapter19: addOneInt' :: IO ()
+ Chapter19: data State a b
+ Chapter19: data Tree a
+ Chapter19: egTree :: Tree String
+ Chapter19: identity :: Identity a -> a
+ Chapter19: instance GHC.Base.Applicative (Chapter19.State a)
+ Chapter19: instance GHC.Base.Applicative Chapter19.Tree
+ Chapter19: instance GHC.Base.Functor (Chapter19.State a)
+ Chapter19: instance GHC.Base.Functor Chapter19.Tree
+ Chapter19: instance GHC.Base.Monad (Chapter19.State a)
+ Chapter19: instance GHC.Classes.Eq a => GHC.Classes.Eq (Chapter19.Tree a)
+ Chapter19: instance GHC.Classes.Ord a => GHC.Classes.Ord (Chapter19.Tree a)
+ Chapter19: instance GHC.Show.Show a => GHC.Show.Show (Chapter19.Tree a)
+ Chapter19: lookup :: Eq a => a -> Table a -> Integer
+ Chapter19: nNode :: Eq a => a -> Table a -> (Table a, Integer)
+ Chapter19: numTree :: Eq a => Tree a -> Tree Integer
+ Chapter19: numberNode :: Eq a => a -> State a Integer
+ Chapter19: numberTree :: Eq a => Tree a -> State a (Tree Integer)
+ Chapter19: runST :: State a b -> b
+ Chapter19: sTree :: Tree Integer -> Integer
+ Chapter19: sTree' :: Tree Integer -> Integer
+ Chapter19: sumTree :: Tree Integer -> Identity Integer
+ Chapter19: type Table a = [a]
+ Chapter21: aFac :: Integer -> Integer -> Integer
+ Chapter21: exam1 :: (Num a, Enum a) => a -> [a]
+ Chapter21: exam2 :: (Num a, Enum a) => a -> [a]
+ Chapter21: exam3 :: (Num a, Enum a) => a -> [a]
+ Chapter21: exam4 :: (Num a, Enum a) => a -> [a]
+ Chapter21: fac :: Integer -> Integer
+ Chapter21: facFold :: (Num b, Enum b) => b -> b
+ Chapter21: fib :: Integer -> Integer
+ Chapter21: fibP :: Integer -> (Integer, Integer)
+ Chapter21: fibs :: [Integer]
+ Chapter21: foldEx1 :: (Eq a, Num a, Enum a) => a -> Bool
+ Chapter21: iSort :: Ord a => [a] -> [a]
+ Chapter21: ins :: Ord a => a -> [a] -> [a]
+ Chapter21: mLen :: Eq a => [a] -> [a] -> Integer
+ Chapter21: mSort :: Ord a => [a] -> [a]
+ Chapter21: map :: Foldable t => (a -> b) -> t a -> [b]
+ Chapter21: maxLen :: Eq a => [a] -> [a] -> Int -> Int -> Int
+ Chapter21: maxTab :: Eq a => [a] -> [a] -> [[Int]]
+ Chapter21: mer :: Ord a => [a] -> [a] -> [a]
+ Chapter21: mult :: (Eq t, Num t, Num a) => a -> t -> a
+ Chapter21: newFac :: Integer -> Integer
+ Chapter21: qSort :: Ord a => [a] -> [a]
+ Chapter21: rev1 :: [a] -> [a]
+ Chapter21: rev2 :: [a] -> [a]
+ Chapter21: russ :: forall {t} {a}. (Num a, Integral t) => a -> t -> a
+ Chapter21: shunt :: [a] -> [a] -> [a]
+ Chapter21: sq :: Num a => a -> a
+ Chapter21: sumList :: [Integer] -> Integer
+ Chapter21: sumSquares :: Integer -> Integer
+ MineRandom: randomGrid :: Int -> Int -> Int -> [[Bool]]
+ MineRandom: randomGridDyn :: Int -> Int -> Int -> Int -> [[Bool]]
+ Minesweeper: add3 :: AddThree a => a -> a -> a -> a
+ Minesweeper: addOffset :: AddThree a => [a] -> [a]
+ Minesweeper: appLeft :: (a -> b) -> (a, c) -> (b, c)
+ Minesweeper: class AddThree a
+ Minesweeper: countConfig :: [[Bool]] -> [[Int]]
+ Minesweeper: countConfigLess :: [[Bool]] -> [[Int]]
+ Minesweeper: instance Minesweeper.AddThree GHC.Types.Int
+ Minesweeper: instance Minesweeper.AddThree [GHC.Types.Int]
+ Minesweeper: makeNumeric :: [[Bool]] -> [[Int]]
+ Minesweeper: nbhrs :: [[Int]] -> (Int, Int) -> [(Int, Int)]
+ Minesweeper: nullNbhrs :: [[Int]] -> (Int, Int) -> [(Int, Int)]
+ Minesweeper: pad :: Int -> String -> String
+ Minesweeper: playGame :: IO ()
+ Minesweeper: showCell :: Bool -> Int -> String
+ Minesweeper: showGrid :: [[Int]] -> String
+ Minesweeper: showGrid3 :: IO ()
+ Minesweeper: showPlay :: [[Bool]] -> [[Int]] -> String
+ Minesweeper: showTest1 :: IO ()
+ Minesweeper: showTest2 :: IO ()
+ Minesweeper: showTest3 :: IO ()
+ Minesweeper: showing :: [[Bool]]
+ Minesweeper: test1 :: [[Bool]]
+ Minesweeper: test3 :: [[Bool]]
+ Minesweeper: tester3 :: IO ()
+ Minesweeper: type Config = [[Bool]]
+ Minesweeper: type Count = [[Int]]
+ Minesweeper: uncoverNbhrs :: [[Int]] -> [(Int, Int)] -> (Int, Int) -> [[Bool]] -> [[Bool]]
+ Minesweeper: uncoverNbhrsList :: [[Int]] -> [(Int, Int)] -> [(Int, Int)] -> [[Bool]] -> [[Bool]]
+ Minesweeper: update :: Int -> (a -> a) -> [a] -> [a]
+ Minesweeper: updateArray :: Int -> Int -> a -> [[a]] -> [[a]]
+ Minesweeper: zero :: AddThree a => a
+ Minesweeper: zipOffset3 :: (a -> a -> a -> a) -> a -> [a] -> [a]
+ Minesweeper2: (!!!) :: [[a]] -> (Int, Int) -> a
+ Minesweeper2: add3 :: AddThree a => a -> a -> a -> a
+ Minesweeper2: addOffset :: AddThree a => [a] -> [a]
+ Minesweeper2: appLeft :: (a -> b) -> (a, c) -> (b, c)
+ Minesweeper2: class AddThree a
+ Minesweeper2: closure :: [[Int]] -> (Int, Int) -> [(Int, Int)]
+ Minesweeper2: countConfig :: [[Bool]] -> [[Int]]
+ Minesweeper2: countConfigLess :: [[Bool]] -> [[Int]]
+ Minesweeper2: doClosure :: [[Int]] -> (Int, Int) -> [(Int, Int)] -> [(Int, Int)]
+ Minesweeper2: doClosureList :: [[Int]] -> [(Int, Int)] -> [(Int, Int)] -> [(Int, Int)]
+ Minesweeper2: fitRange :: Int -> Int -> Int
+ Minesweeper2: fixSplit :: [Equation] -> [Equation]
+ Minesweeper2: fixpt :: Eq a => (a -> a) -> a -> a
+ Minesweeper2: getInfo :: [[Int]] -> [[Bool]] -> [[Bool]] -> Int -> Int -> Equations
+ Minesweeper2: getInfoCell :: [[Int]] -> [[Bool]] -> [[Bool]] -> Int -> Int -> Equation
+ Minesweeper2: instance Minesweeper2.AddThree GHC.Types.Int
+ Minesweeper2: instance Minesweeper2.AddThree [GHC.Types.Int]
+ Minesweeper2: listDiff :: Eq a => [a] -> [a] -> [a]
+ Minesweeper2: makeNumeric :: [[Bool]] -> [[Int]]
+ Minesweeper2: nbhrs :: [[Int]] -> (Int, Int) -> [(Int, Int)]
+ Minesweeper2: pad :: Int -> String -> String
+ Minesweeper2: playGame :: Int -> Int -> IO ()
+ Minesweeper2: showCell :: Bool -> Bool -> Int -> String
+ Minesweeper2: showCol :: Int -> String
+ Minesweeper2: showEquation :: Equation -> String
+ Minesweeper2: showEquations :: [Equation] -> [Char]
+ Minesweeper2: showGrid :: [[Int]] -> String
+ Minesweeper2: showInfo :: [[Int]] -> [[Bool]] -> [[Bool]] -> Int -> Int -> String
+ Minesweeper2: showInfoCell :: [[Int]] -> [[Bool]] -> [[Bool]] -> Int -> Int -> String
+ Minesweeper2: showPlay :: [[Bool]] -> [[Bool]] -> [[Int]] -> String
+ Minesweeper2: showPoint :: (Int, Int) -> String
+ Minesweeper2: showPoints :: [(Int, Int)] -> String
+ Minesweeper2: showRow :: Int -> String
+ Minesweeper2: splitEq :: Equation -> Equation -> Equation
+ Minesweeper2: splitEqs :: [Equation] -> [Equation]
+ Minesweeper2: subList :: Eq a => [a] -> [a] -> Bool
+ Minesweeper2: test1 :: [[Bool]]
+ Minesweeper2: type Config = [[Bool]]
+ Minesweeper2: type Count = [[Int]]
+ Minesweeper2: type Equation = (Int, [(Int, Int)])
+ Minesweeper2: type Equations = [Equation]
+ Minesweeper2: uncoverClosure :: [[Int]] -> (Int, Int) -> [[Bool]] -> [[Bool]]
+ Minesweeper2: update :: Int -> (a -> a) -> [a] -> [a]
+ Minesweeper2: updateArray :: Int -> Int -> a -> [[a]] -> [[a]]
+ Minesweeper2: zero :: AddThree a => a
+ Minesweeper2: zipOffset3 :: (a -> a -> a -> a) -> a -> [a] -> [a]
+ Minesweeper3: (!!!) :: [[a]] -> (Int, Int) -> a
+ Minesweeper3: add3 :: AddThree a => a -> a -> a -> a
+ Minesweeper3: addOffset :: AddThree a => [a] -> [a]
+ Minesweeper3: appLeft :: (a -> b) -> (a, c) -> (b, c)
+ Minesweeper3: class AddThree a
+ Minesweeper3: closure :: [[Int]] -> (Int, Int) -> [(Int, Int)]
+ Minesweeper3: countConfig :: [[Bool]] -> [[Int]]
+ Minesweeper3: countConfigLess :: [[Bool]] -> [[Int]]
+ Minesweeper3: deterNeg :: Equation -> Bool
+ Minesweeper3: deterPos :: Equation -> Bool
+ Minesweeper3: determined :: Equation -> Bool
+ Minesweeper3: doClosure :: [[Int]] -> (Int, Int) -> [(Int, Int)] -> [(Int, Int)]
+ Minesweeper3: doClosureList :: [[Int]] -> [(Int, Int)] -> [(Int, Int)] -> [(Int, Int)]
+ Minesweeper3: fitRange :: Int -> Int -> Int
+ Minesweeper3: fixSplit :: [Equation] -> [Equation]
+ Minesweeper3: fixpt :: Eq a => (a -> a) -> a -> a
+ Minesweeper3: getInfo :: [[Int]] -> [[Bool]] -> [[Bool]] -> Int -> Int -> Equations
+ Minesweeper3: getInfoCell :: [[Int]] -> [[Bool]] -> [[Bool]] -> Int -> Int -> Equation
+ Minesweeper3: instance Minesweeper3.AddThree GHC.Types.Int
+ Minesweeper3: instance Minesweeper3.AddThree [GHC.Types.Int]
+ Minesweeper3: listDiff :: Eq a => [a] -> [a] -> [a]
+ Minesweeper3: makeNeg :: [Equation] -> [(Int, Int)]
+ Minesweeper3: makeNumeric :: [[Bool]] -> [[Int]]
+ Minesweeper3: makePos :: [Equation] -> [(Int, Int)]
+ Minesweeper3: nbhrs :: [[Int]] -> (Int, Int) -> [(Int, Int)]
+ Minesweeper3: pad :: Int -> String -> String
+ Minesweeper3: playAuto :: [[Bool]] -> [[Int]] -> [[Bool]] -> [[Bool]] -> [(Int, Int)] -> IO ()
+ Minesweeper3: playAutoOne :: [[Bool]] -> [[Int]] -> [[Bool]] -> [[Bool]] -> Int -> Int -> ([[Bool]], [[Bool]])
+ Minesweeper3: playGame :: Int -> Int -> IO ()
+ Minesweeper3: playGameGrid :: [[Bool]] -> [[Int]] -> [[Bool]] -> [[Bool]] -> IO ()
+ Minesweeper3: showCell :: Bool -> Bool -> Int -> String
+ Minesweeper3: showCol :: Int -> String
+ Minesweeper3: showEquation :: Equation -> String
+ Minesweeper3: showEquations :: [Equation] -> [Char]
+ Minesweeper3: showGrid :: [[Int]] -> String
+ Minesweeper3: showInfo :: [[Int]] -> [[Bool]] -> [[Bool]] -> Int -> Int -> String
+ Minesweeper3: showInfoCell :: [[Int]] -> [[Bool]] -> [[Bool]] -> Int -> Int -> String
+ Minesweeper3: showPlay :: [[Bool]] -> [[Bool]] -> [[Int]] -> String
+ Minesweeper3: showPoint :: (Int, Int) -> String
+ Minesweeper3: showPoints :: [(Int, Int)] -> String
+ Minesweeper3: showRow :: Int -> String
+ Minesweeper3: splitEq :: Equation -> Equation -> Equation
+ Minesweeper3: splitEqs :: [Equation] -> [Equation]
+ Minesweeper3: subList :: Eq a => [a] -> [a] -> Bool
+ Minesweeper3: test1 :: [[Bool]]
+ Minesweeper3: type Config = [[Bool]]
+ Minesweeper3: type Count = [[Int]]
+ Minesweeper3: type Equation = (Int, [(Int, Int)])
+ Minesweeper3: type Equations = [Equation]
+ Minesweeper3: uncoverClosure :: [[Int]] -> (Int, Int) -> [[Bool]] -> [[Bool]]
+ Minesweeper3: update :: Int -> (a -> a) -> [a] -> [a]
+ Minesweeper3: updateArray :: Int -> Int -> a -> [[a]] -> [[a]]
+ Minesweeper3: updateMarkByEqs :: [Equation] -> [[Bool]] -> [[Bool]]
+ Minesweeper3: updateShowByEqs :: [Equation] -> [[Int]] -> [[Bool]] -> [[Bool]]
+ Minesweeper3: zero :: AddThree a => a
+ Minesweeper3: zipOffset3 :: (a -> a -> a -> a) -> a -> [a] -> [a]
+ Minesweeper4: (!!!) :: [[a]] -> Point -> a
+ Minesweeper4: add3 :: AddThree a => a -> a -> a -> a
+ Minesweeper4: addOffset :: AddThree a => [a] -> [a]
+ Minesweeper4: appLeft :: (a -> b) -> (a, c) -> (b, c)
+ Minesweeper4: class AddThree a
+ Minesweeper4: closure :: [[Int]] -> Point -> [Point]
+ Minesweeper4: countConfig :: [[Bool]] -> [[Int]]
+ Minesweeper4: countConfigLess :: [[Bool]] -> [[Int]]
+ Minesweeper4: deterNeg :: Equation -> Bool
+ Minesweeper4: deterPos :: Equation -> Bool
+ Minesweeper4: determined :: Equation -> Bool
+ Minesweeper4: doClosure :: [[Int]] -> Point -> [Point] -> [Point]
+ Minesweeper4: doClosureList :: [[Int]] -> [Point] -> [Point] -> [Point]
+ Minesweeper4: fitRange :: Int -> Int -> Int
+ Minesweeper4: fixSplit :: [Equation] -> [Equation]
+ Minesweeper4: fixpt :: Eq a => (a -> a) -> a -> a
+ Minesweeper4: getInfo :: [[Int]] -> [[Bool]] -> [[Bool]] -> Point -> Equations
+ Minesweeper4: getInfoCell :: [[Int]] -> [[Bool]] -> [[Bool]] -> Point -> Equation
+ Minesweeper4: helpInfo :: String
+ Minesweeper4: instance Minesweeper4.AddThree GHC.Types.Int
+ Minesweeper4: instance Minesweeper4.AddThree [GHC.Types.Int]
+ Minesweeper4: listDiff :: Eq a => [a] -> [a] -> [a]
+ Minesweeper4: makeNeg :: [Equation] -> [Point]
+ Minesweeper4: makeNumeric :: [[Bool]] -> [[Int]]
+ Minesweeper4: makePos :: [Equation] -> [Point]
+ Minesweeper4: nbhrs :: [[Int]] -> Point -> [Point]
+ Minesweeper4: pad :: Int -> String -> String
+ Minesweeper4: playAuto :: [[Bool]] -> [[Int]] -> [[Bool]] -> [[Bool]] -> [Point] -> IO ()
+ Minesweeper4: playAutoOne :: [[Bool]] -> [[Int]] -> [[Bool]] -> [[Bool]] -> Point -> ([[Bool]], [[Bool]])
+ Minesweeper4: playGame :: Int -> Int -> IO ()
+ Minesweeper4: playGameGrid :: [[Bool]] -> [[Int]] -> [[Bool]] -> [[Bool]] -> IO ()
+ Minesweeper4: showCell :: Bool -> Bool -> Int -> String
+ Minesweeper4: showCol :: Int -> String
+ Minesweeper4: showEquation :: Equation -> String
+ Minesweeper4: showEquations :: Equations -> String
+ Minesweeper4: showGrid :: [[Int]] -> String
+ Minesweeper4: showInfo :: [[Int]] -> [[Bool]] -> [[Bool]] -> Point -> String
+ Minesweeper4: showInfoCell :: [[Int]] -> [[Bool]] -> [[Bool]] -> Point -> String
+ Minesweeper4: showPlay :: [[Bool]] -> [[Bool]] -> [[Int]] -> String
+ Minesweeper4: showPoint :: Point -> String
+ Minesweeper4: showPoints :: [Point] -> String
+ Minesweeper4: showRow :: Int -> String
+ Minesweeper4: splitEq :: Equation -> Equation -> Equation
+ Minesweeper4: splitEqs :: [Equation] -> [Equation]
+ Minesweeper4: subList :: Eq a => [a] -> [a] -> Bool
+ Minesweeper4: test1 :: [[Bool]]
+ Minesweeper4: type Config = [[Bool]]
+ Minesweeper4: type Count = [[Int]]
+ Minesweeper4: type Equation = (Int, [Point])
+ Minesweeper4: type Equations = [Equation]
+ Minesweeper4: type Point = (Int, Int)
+ Minesweeper4: uncoverClosure :: [[Int]] -> Point -> [[Bool]] -> [[Bool]]
+ Minesweeper4: update :: Int -> (a -> a) -> [a] -> [a]
+ Minesweeper4: updateArray :: Point -> a -> [[a]] -> [[a]]
+ Minesweeper4: updateMarkByEqs :: [Equation] -> [[Bool]] -> [[Bool]]
+ Minesweeper4: updateShowByEqs :: [Equation] -> [[Int]] -> [[Bool]] -> [[Bool]]
+ Minesweeper4: zero :: AddThree a => a
+ Minesweeper4: zipOffset3 :: (a -> a -> a -> a) -> a -> [a] -> [a]
+ Minesweeper5: (!!!) :: [[a]] -> Point -> a
+ Minesweeper5: add3 :: AddThree a => a -> a -> a -> a
+ Minesweeper5: addOffset :: AddThree a => [a] -> [a]
+ Minesweeper5: appLeft :: (a -> b) -> (a, c) -> (b, c)
+ Minesweeper5: class AddThree a
+ Minesweeper5: closure :: [[Int]] -> Point -> [Point]
+ Minesweeper5: countConfig :: [[Bool]] -> [[Int]]
+ Minesweeper5: countConfigLess :: [[Bool]] -> [[Int]]
+ Minesweeper5: deterNeg :: Equation -> Bool
+ Minesweeper5: deterPos :: Equation -> Bool
+ Minesweeper5: determined :: Equation -> Bool
+ Minesweeper5: doClosure :: [[Int]] -> Point -> [Point] -> [Point]
+ Minesweeper5: doClosureList :: [[Int]] -> [Point] -> [Point] -> [Point]
+ Minesweeper5: fitRange :: Int -> Int -> Int
+ Minesweeper5: fixSplit :: [Equation] -> [Equation]
+ Minesweeper5: fixpt :: Eq a => (a -> a) -> a -> a
+ Minesweeper5: getInfo :: [[Int]] -> [[Bool]] -> [[Bool]] -> Point -> Equations
+ Minesweeper5: getInfoCell :: [[Int]] -> [[Bool]] -> [[Bool]] -> Point -> Equation
+ Minesweeper5: getInput :: Int -> IO (Char, Point)
+ Minesweeper5: helpInfo :: String
+ Minesweeper5: instance Minesweeper5.AddThree GHC.Types.Int
+ Minesweeper5: instance Minesweeper5.AddThree a => Minesweeper5.AddThree [a]
+ Minesweeper5: listDiff :: Eq a => [a] -> [a] -> [a]
+ Minesweeper5: makeNeg :: [Equation] -> [Point]
+ Minesweeper5: makeNumeric :: [[Bool]] -> [[Int]]
+ Minesweeper5: makePos :: [Equation] -> [Point]
+ Minesweeper5: nbhrs :: [[Int]] -> Point -> [Point]
+ Minesweeper5: pad :: Int -> String -> String
+ Minesweeper5: playAuto :: [[Bool]] -> [[Int]] -> [[Bool]] -> [[Bool]] -> [Point] -> IO ()
+ Minesweeper5: playAutoOne :: [[Bool]] -> [[Int]] -> [[Bool]] -> [[Bool]] -> Point -> ([[Bool]], [[Bool]])
+ Minesweeper5: playGame :: Int -> Int -> IO ()
+ Minesweeper5: playGameGrid :: [[Bool]] -> [[Int]] -> [[Bool]] -> [[Bool]] -> IO ()
+ Minesweeper5: showCell :: Bool -> Bool -> Int -> String
+ Minesweeper5: showCol :: Int -> String
+ Minesweeper5: showEquation :: Equation -> String
+ Minesweeper5: showEquations :: Equations -> String
+ Minesweeper5: showGrid :: [[Int]] -> String
+ Minesweeper5: showInfo :: [[Int]] -> [[Bool]] -> [[Bool]] -> Point -> String
+ Minesweeper5: showInfoCell :: [[Int]] -> [[Bool]] -> [[Bool]] -> Point -> String
+ Minesweeper5: showPlay :: [[Bool]] -> [[Bool]] -> [[Int]] -> String
+ Minesweeper5: showPoint :: Point -> String
+ Minesweeper5: showPoints :: [Point] -> String
+ Minesweeper5: showRow :: Int -> String
+ Minesweeper5: splitEq :: Equation -> Equation -> Equation
+ Minesweeper5: splitEqs :: [Equation] -> [Equation]
+ Minesweeper5: subList :: Eq a => [a] -> [a] -> Bool
+ Minesweeper5: test1 :: [[Bool]]
+ Minesweeper5: type Config = [[Bool]]
+ Minesweeper5: type Count = [[Int]]
+ Minesweeper5: type Equation = (Int, [Point])
+ Minesweeper5: type Equations = [Equation]
+ Minesweeper5: type Point = (Int, Int)
+ Minesweeper5: uncoverClosure :: [[Int]] -> Point -> [[Bool]] -> [[Bool]]
+ Minesweeper5: update :: Int -> (a -> a) -> [a] -> [a]
+ Minesweeper5: updateArray :: Point -> a -> [[a]] -> [[a]]
+ Minesweeper5: updateMarkByEqs :: [Equation] -> [[Bool]] -> [[Bool]]
+ Minesweeper5: updateShowByEqs :: [Equation] -> [[Int]] -> [[Bool]] -> [[Bool]]
+ Minesweeper5: zero :: AddThree a => a
+ Minesweeper5: zipOffset3 :: (a -> a -> a -> a) -> a -> [a] -> [a]
+ Palin: change :: String -> String
+ Palin: convert :: Char -> Char
+ Palin: disregard :: String -> String
+ Palin: isCap :: Char -> Bool
+ Palin: notPunct :: Char -> Bool
+ Palin: palin :: String -> Bool
+ Palin: remove :: String -> String
+ Palin: rev :: String -> String
+ Palin: simplePalin :: String -> Bool
+ Test: checkInverse :: String -> Bool
+ Test: prop_Hufmann :: [Char] -> Property

Files

Chapter18.hs view
@@ -12,16 +12,14 @@ module Chapter18 where  import Prelude hiding (lookup)-import System.IO -import Control.Monad (liftM, ap)-import Control.Monad.Identity+import System.IO import Chapter8 (getInt) import Data.Time import System.Locale hiding (defaultTimeLocale) import System.IO.Unsafe (unsafePerformIO) --- Programming with monads--- ^^^^^^^^^^^^^^^^^^^^^^^+-- I/O programming+-- ^^^^^^^^^^^^^^^   -- The basics of input/output@@ -32,8 +30,8 @@ --  getLine :: IO String --  getChar :: IO Char --- Text strings are written using ---  +-- Text strings are written using+-- --  putStr :: String -> IO () --  putStrLn :: String -> IO () @@ -65,7 +63,7 @@  sumInts s   = do n <- getInt-       if n==0 +       if n==0           then return s           else sumInts (s+n) @@ -74,7 +72,7 @@ sumAcc :: Integer -> [Integer] -> Integer  sumAcc s [] = s-sumAcc s (n:ns) +sumAcc s (n:ns)   = if n==0        then s        else sumAcc (s+n) ns@@ -98,7 +96,7 @@  copyInteract :: IO () -copyInteract = +copyInteract =     do       hSetBuffering stdin LineBuffering       copyEOF@@ -106,12 +104,12 @@  copyEOF :: IO () -copyEOF = -    do +copyEOF =+    do       eof <- isEOF-      if eof  -        then return () -        else do line <- getLine +      if eof+        then return ()+        else do line <- getLine                 putStrLn line                 copyEOF @@ -127,216 +125,16 @@ -- Generating random numbers  randomInt :: Integer -> IO Integer-randomInt n = +randomInt n =     do       time <- getCurrentTime       return ( (`rem` n) $ read $ take 6 $ formatTime defaultTimeLocale "%q" time)-      + randInt :: Integer -> Integer-randInt = unsafePerformIO . randomInt -      +randInt = unsafePerformIO . randomInt   -- The calculator -- ^^^^^^^^^^^^^^  -- This is available separately in the Calculator directory.----- The do notation revisited--- ^^^^^^^^^^^^^^^^^^^^^^^^^--addOneInt :: IO ()--addOneInt -  = do line <- getLine-       putStrLn (show (1 + read line :: Int))       --addOneInt' -  = getLine >>= \line ->-    putStrLn (show (1 + read line :: Int))     ---- Monads for Functional Programming--- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---- The definition of the Monad class---  class Monad m where---    (>>=)  :: m a -> (a -> m b) -> m b---    return :: a -> m a---    fail   :: String -> m a---- Kelisli composition for monadic functions.---- (>@>) :: Monad m => (a -> m b) ->---                     (b -> m c) ->---                     (a -> m c)---- f >@> g = \ x -> (f x) >>= g----- Some examples of monads--- ^^^^^^^^^^^^^^^^^^^^^^^---- Some examples from the standard prelude.---- The list monad----  instance Monad [] where---    xs >>= f  = concat (map f xs)---    return x  = [x]---    zero      = []---- The Maybe monad----  instance Monad Maybe where---    (Just x) >>= k  =  k x---    Nothing  >>= k  =  Nothing---    return          =  Just----- The parsing monad----  data SParse a b = SParse (Parse a b)----  instance Monad (SParse a) where---    return x = SParse (succeed x)---    zero     = SParse fail---    (SParse pr) >>= f ---      = SParse (\s -> concat [ sparse (f x) rest | (x,rest) <- pr st ])----  sparse :: SParse a b -> Parse a b---  sparse (SParse pr) = pr---- A state monad (the state need not be a table; this example is designed--- to support the example discussed below.)--type Table a = [a]--data State a b = State (Table a -> (Table a , b))--instance Monad (State a) where--  return x = State (\tab -> (tab,x))--  (State st) >>= f -    = State (\tab -> let -                     (newTab,y)    = st tab-                     (State trans) = f y -                     in-                     trans newTab)--instance Applicative (State a) where-  pure = return-  (<*>) = ap--instance Functor (State a) where-  fmap = liftM----- Example: Monadic computation over trees--- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---- A type of binary trees.--data Tree a = Nil | Node a (Tree a) (Tree a)-              deriving (Eq,Ord,Show)---- Summing a tree of integers---- A direct solution:--sTree :: Tree Integer -> Integer--sTree Nil            = 0-sTree (Node n t1 t2) = n + sTree t1 + sTree t2---- A monadic solution: first giving a value of type Identity Int ...--sumTree :: Tree Integer -> Identity Integer--sumTree Nil = return 0--sumTree (Node n t1 t2)-  = do num <- return n-       s1  <- sumTree t1-       s2  <- sumTree t2-       return (num + s1 + s2)---- ... then adapted to give an Int solution--sTree' :: Tree Integer -> Integer--sTree' = identity . sumTree--identity :: Identity a -> a--identity (Identity x) = x---- Using a state monad in a tree calculation--- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---- The top level function ...--numTree :: Eq a => Tree a -> Tree Integer---- ... and the function which does all the work:--numberTree :: Eq a => Tree a -> State a (Tree Integer)---- Its structure mirrors exactly the structure of the earlier program to--- sum the tree.--numberTree Nil = return Nil--numberTree (Node x t1 t2)-  = do num <- numberNode x-       nt1 <- numberTree t1-       nt2 <- numberTree t2-       return (Node num nt1 nt2)---- The work of the algorithm is done node by node, hence the function--numberNode :: Eq a => a -> State a Integer--numberNode x = State (nNode x)----  --- Looking up a value in the table; will side-effect the table if the value--- is not present.--nNode :: Eq a => a -> (Table a -> (Table a , Integer))-nNode x table-  | elem x table        = (table      , lookup x table)-  | otherwise           = (table++[x] , integerLength table)-    where-      integerLength = toInteger.length-  --- Looking up a value in the table when known to be present--lookup :: Eq a => a -> Table a -> Integer--lookup x tab = -    locate 0 tab-           where-             locate n (y:ys) = -                 if x==y then n else locate (n+1) ys---- Extracting a value froma state monad.--runST :: State a b -> b-runST (State st) = snd (st [])---- The top-level function defined eventually.--numTree = runST . numberTree---- Example tree--egTree :: Tree String- -egTree = Node "Moon"-               (Node "Ahmet" Nil Nil)-               (Node "Dweezil"  -                        (Node "Ahmet" Nil Nil) -                        (Node "Moon" Nil Nil))-
+ Chapter19.hs view
@@ -0,0 +1,303 @@+-----------------------------------------------------------------------+--+--  Haskell: The Craft of Functional Programming+--  Simon Thompson+--  (c) Addison-Wesley, 1996-2011.+--+--  Chapter 19+--+-----------------------------------------------------------------------+++module Chapter19 where++import Prelude hiding (lookup)+import Control.Monad (liftM, ap)+import Control.Monad.Identity++-- Abstraction: functors, monads and folding+-- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^+++-- Abstraction+-- ^^^^^^^^^^^++-- Spotting the pattern of mapping along a list ...++--  map :: (a -> b) -> [a] -> [b]++-- ... and the pattern of folding along a list.++--  foldr :: (a -> b -> b) -> b -> [a] -> b+--+--  foldr g s []     = s+--  foldr g s (x:xs) = g x (foldr g s xs)+++-- The Functor class+-- ^^^^^^^^^^^^^^^^^++--  class Functor g where+--    fmap :: (a -> b) -> g a -> g b++-- A first example, the Maybe type; Functor Maybe is already an instance+-- in the standard libraries, so this is given as a comment.++--  instance Functor Maybe where+--    fmap f Nothing  = Nothing+--    fmap f (Just x) = Just (f x)++-- The list instance is standard too.++--  instance Functor [] where+--    fmap f []     = []+--    fmap f (x:xs) = f x : fmap f xs++-- Instances for the tree type used later in this chapter (Section+-- 19.5, "Example: monadic computation over trees") are given as real+-- code once that type has been declared, below.+++-- The Applicative class+-- ^^^^^^^^^^^^^^^^^^^^^++--  class Functor g => Applicative g where+--    pure   :: a -> g a+--    (<*>)  :: g (a -> b) -> g a -> g b+--    liftA2 :: (a -> b -> c) -> g a -> g b -> g c++-- Applicative Maybe is already an instance in the standard libraries,+-- so both of the styles of definition discussed in the book -- via+-- liftA2, and via <*> -- are given here as comments.++--  instance Applicative Maybe where+--    pure x = Just x+--+--    liftA2 f (Just x) (Just y) = Just (f x y)+--    liftA2 _ _        _        = Nothing++--  instance Applicative Maybe where+--    ...+--    (Just f) <*> (Just x) = Just (f x)+--    _        <*> _        = Nothing++-- The Applicative instance for the tree type is given as real code+-- once that type has been declared, below.+++-- The do notation revisited+-- ^^^^^^^^^^^^^^^^^^^^^^^^^++addOneInt :: IO ()++addOneInt+  = do line <- getLine+       putStrLn (show (1 + read line :: Int))++addOneInt'+  = getLine >>= \line ->+    putStrLn (show (1 + read line :: Int))++-- Monads: languages for functional programming+-- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^++-- The definition of the Monad class+--  class Monad m where+--    (>>=)  :: m a -> (a -> m b) -> m b+--    return :: a -> m a+--    fail   :: String -> m a++-- Kelisli composition for monadic functions.++-- (>@>) :: Monad m => (a -> m b) ->+--                     (b -> m c) ->+--                     (a -> m c)++-- f >@> g = \ x -> (f x) >>= g+++-- Some examples of monads+-- ^^^^^^^^^^^^^^^^^^^^^^^++-- Some examples from the standard prelude.++-- The list monad++--  instance Monad [] where+--    xs >>= f  = concat (map f xs)+--    return x  = [x]+--    zero      = []++-- The Maybe monad++--  instance Monad Maybe where+--    (Just x) >>= k  =  k x+--    Nothing  >>= k  =  Nothing+--    return          =  Just+++-- The parsing monad++--  data SParse a b = SParse (Parse a b)++--  instance Monad (SParse a) where+--    return x = SParse (succeed x)+--    zero     = SParse fail+--    (SParse pr) >>= f+--      = SParse (\s -> concat [ sparse (f x) rest | (x,rest) <- pr st ])++--  sparse :: SParse a b -> Parse a b+--  sparse (SParse pr) = pr++-- A state monad (the state need not be a table; this example is designed+-- to support the example discussed below.)++type Table a = [a]++data State a b = State (Table a -> (Table a , b))++instance Monad (State a) where++  return x = State (\tab -> (tab,x))++  (State st) >>= f+    = State (\tab -> let+                     (newTab,y)    = st tab+                     (State trans) = f y+                     in+                     trans newTab)++instance Applicative (State a) where+  pure = return+  (<*>) = ap++instance Functor (State a) where+  fmap = liftM+++-- Example: Monadic computation over trees+-- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^++-- A type of binary trees.++data Tree a = Nil | Node a (Tree a) (Tree a)+              deriving (Eq,Ord,Show)++-- Tree as an instance of Functor: mapping f over every value stored+-- at a node.++instance Functor Tree where+  fmap f Nil            = Nil+  fmap f (Node x t1 t2) = Node (f x) (fmap f t1) (fmap f t2)++-- Tree as an instance of Applicative, following the same pattern as+-- the liftA2 definition for Maybe above: pure builds a single-node+-- tree, and liftA2 f applies f pointwise to two trees of the same+-- shape, returning Nil as soon as either side runs out of structure.++instance Applicative Tree where+  pure x = Node x Nil Nil++  liftA2 f Nil _ = Nil+  liftA2 f _ Nil = Nil+  liftA2 f (Node x t1 t2) (Node y s1 s2)+    = Node (f x y) (liftA2 f t1 s1) (liftA2 f t2 s2)++-- Summing a tree of integers++-- A direct solution:++sTree :: Tree Integer -> Integer++sTree Nil            = 0+sTree (Node n t1 t2) = n + sTree t1 + sTree t2++-- A monadic solution: first giving a value of type Identity Int ...++sumTree :: Tree Integer -> Identity Integer++sumTree Nil = return 0++sumTree (Node n t1 t2)+  = do num <- return n+       s1  <- sumTree t1+       s2  <- sumTree t2+       return (num + s1 + s2)++-- ... then adapted to give an Int solution++sTree' :: Tree Integer -> Integer++sTree' = identity . sumTree++identity :: Identity a -> a++identity (Identity x) = x++-- Using a state monad in a tree calculation+-- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^++-- The top level function ...++numTree :: Eq a => Tree a -> Tree Integer++-- ... and the function which does all the work:++numberTree :: Eq a => Tree a -> State a (Tree Integer)++-- Its structure mirrors exactly the structure of the earlier program to+-- sum the tree.++numberTree Nil = return Nil++numberTree (Node x t1 t2)+  = do num <- numberNode x+       nt1 <- numberTree t1+       nt2 <- numberTree t2+       return (Node num nt1 nt2)++-- The work of the algorithm is done node by node, hence the function++numberNode :: Eq a => a -> State a Integer++numberNode x = State (nNode x)++--+-- Looking up a value in the table; will side-effect the table if the value+-- is not present.++nNode :: Eq a => a -> (Table a -> (Table a , Integer))+nNode x table+  | elem x table        = (table      , lookup x table)+  | otherwise           = (table++[x] , integerLength table)+    where+      integerLength = toInteger.length++-- Looking up a value in the table when known to be present++lookup :: Eq a => a -> Table a -> Integer++lookup x tab =+    locate 0 tab+           where+             locate n (y:ys) =+                 if x==y then n else locate (n+1) ys++-- Extracting a value froma state monad.++runST :: State a b -> b+runST (State st) = snd (st [])++-- The top-level function defined eventually.++numTree = runST . numberTree++-- Example tree++egTree :: Tree String++egTree = Node "Moon"+               (Node "Ahmet" Nil Nil)+               (Node "Dweezil"+                        (Node "Ahmet" Nil Nil)+                        (Node "Moon" Nil Nil))
− Chapter19/ParseLib.hs
@@ -1,143 +0,0 @@----------------------------------------------------------------------------- ---  Haskell: The Craft of Functional Programming, 3e---  Simon Thompson---  (c) Addison-Wesley, 1996-2011.--- ---  ParseLib.hs--- ---  Library functions for parsing   ---      Note that this is not a monadic approach to parsing.    --- ----------------------------------------------------------------------------                                                                                                  --module ParseLib where--import Control.Monad (liftM, ap)-import Data.Char--infixr 5 >*>---   --- The type of parsers.                     ---  -type Parse a b = [a] -> [(b,[a])]---  --- Some basic parsers                       ---  ---  --- Fail on any input.                       ---  -none :: Parse a b-none inp = []---  --- Succeed, returning the value supplied.               ---  -succeed :: b -> Parse a b -succeed val inp = [(val,inp)]---  --- token t recognises t as the first value in the input.        ---  -token :: Eq a => a -> Parse a a-token t (x:xs) -  | t==x    = [(t,xs)]-  | otherwise   = []-token t []    = []---  --- spot whether an element with a particular property is the    --- first element of input.                      ---  -spot :: (a -> Bool) -> Parse a a-spot p (x:xs) -  | p x     = [(x,xs)]-  | otherwise   = []-spot p []    = []---  --- Examples.                            ---  -bracket = token '('-dig     =  spot isDigit---- Succeeds with value given when the input is empty.--endOfInput :: b -> Parse a b-endOfInput x [] = [(x,[])]-endOfInput x _  = []---  --- Combining parsers                        ---  ---  --- alt p1 p2 recognises anything recogniseed by p1 or by p2.    ---  -alt :: Parse a b -> Parse a b -> Parse a b-alt p1 p2 inp = p1 inp ++ p2 inp-exam1 = (bracket `alt` dig) "234" ---  --- Apply one parser then the second to the result(s) of the first.  ---  --(>*>) :: Parse a b -> Parse a c -> Parse a (b,c)---  -(>*>) p1 p2 inp -  = [((y,z),rem2) | (y,rem1) <- p1 inp , (z,rem2)  <- p2 rem1 ]---  --- Transform the results of the parses according to the function.   ---  -build :: Parse a b -> (b -> c) -> Parse a c-build p f inp = [ (f x,rem) | (x,rem) <- p inp ]---  --- Recognise a list of objects.                 ---  ---  -list :: Parse a b -> Parse a [b]-list p = (succeed []) -         `alt`-         ((p >*> list p) `build` convert)-         where-         convert = uncurry (:)---  --- Some variants...---- A non-empty list of objects.                     ---  -neList   :: Parse a b -> Parse a [b]-neList p = (p  `build` (:[]))-           `alt`-           ((p >*> list p) `build` (uncurry (:)))---- Zero or one object.--optional :: Parse a b -> Parse a [b]-optional p = (succeed []) -             `alt`  -             (p  `build` (:[]))---- A given number of objects.--nTimes :: Int -> Parse a b -> Parse a [b]-nTimes 0 p     = succeed []-nTimes n p     = (p >*> nTimes (n-1) p) `build` (uncurry (:))---  --- Monadic parsing--data SParse a b = SParse (Parse a b)--instance Monad (SParse a) where-  return x = SParse (succeed x)-  (SParse pr) >>= f-    = SParse (\st -> concat [ sparse (f a) rest | (a,rest) <- pr st ])--instance MonadFail (SParse a) where-  fail s   = SParse none--instance Applicative (SParse a) where-  pure = return-  (<*>) = ap--instance Functor (SParse a) where-  fmap = liftM--sparse :: SParse a b -> Parse a b--sparse (SParse pr) = pr--
− Chapter19/Pic.hs
@@ -1,63 +0,0 @@------------------------------------------------------------------------------  Haskell: The Craft of Functional Programming---  Simon Thompson---  (c) Addison-Wesley, 1996-2011.------  Pic.hs--- ---      A deep embedding of pictures-----------------------------------------------------------------------------module Pic where--import Pictures---- Data type representing pictures--data Pic = Horse |-           Above Pic Pic |-           Beside Pic Pic |-           FlipH Pic |-           FlipV Pic ---- Interpreting a Pic as a Picture--interpretPic :: Pic -> Picture--interpretPic Horse = horse-interpretPic (Above pic1 pic2)-  = above (interpretPic pic1)  (interpretPic pic2)-interpretPic (Beside pic1 pic2)-  = beside (interpretPic pic1)  (interpretPic pic2)-interpretPic (FlipH pic)-  = flipH (interpretPic pic)-interpretPic (FlipV pic)-  = flipV (interpretPic pic)---- Tidying up a picture ...---- remove pairs of flips--- push flips through placement above / beside--tidyPic :: Pic -> Pic--tidyPic (FlipV (FlipV pic)) -  = tidyPic pic-tidyPic (FlipV (FlipH pic)) -  = FlipH (tidyPic (FlipV pic)) --tidyPic (FlipV (Above pic1 pic2))-  = Above (tidyPic (FlipV pic1)) (tidyPic (FlipV pic2)) -tidyPic (FlipV (Beside pic1 pic2))-  = Beside (tidyPic (FlipV pic2)) (tidyPic (FlipV pic1)) --tidyPic (FlipH (FlipH pic)) -  = tidyPic pic-  -tidyPic (FlipH (Above pic1 pic2))-  = Above (tidyPic (FlipH pic2)) (tidyPic (FlipH pic1)) -tidyPic (FlipH (Beside pic1 pic2))-  = Beside (tidyPic (FlipH pic1)) (tidyPic (FlipH pic2)) -  
− Chapter19/Pictures.hs
@@ -1,256 +0,0 @@---------------------------------------------------------------------------  Haskell: The Craft of Functional Programming---  Simon Thompson---  (c) Addison-Wesley, 1996-2010.------  Pictures.hs--- ---     An implementation of a type of rectangular pictures  ---     using lists of lists of characters. ------------------------------------------------------------------------------ The basics--- ^^^^^^^^^^--module Pictures where-import Test.QuickCheck---type Picture = [[Char]]---- The example used in Craft2e: a polygon which looks like a horse. Here--- taken to be a 16 by 12 rectangle.--horse :: Picture--horse = [".......##...",-         ".....##..#..",-         "...##.....#.",-         "..#.......#.",-         "..#...#...#.",-         "..#...###.#.",-         ".#....#..##.",-         "..#...#.....",-         "...#...#....",-         "....#..#....",-         ".....#.#....",-         "......##...."]---- Completely white and black pictures.--white :: Picture--white = ["......",-         "......",-         "......",-         "......",-         "......",-         "......"]--black = ["######",-         "######",-         "######",-         "######",-         "######",-         "######"]---- Getting a picture onto the screen.--printPicture :: Picture -> IO ()--printPicture = putStr . concat . map (++"\n")----- Transformations of pictures.--- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^---- Reflection in a vertical mirror.--flipV :: Picture -> Picture--flipV = map reverse---- Reflection in a horizontal mirror.--flipH :: Picture -> Picture--flipH = reverse---- Rotation through 180 degrees, by composing vertical and horizontal--- reflection. Note that it can also be done by flipV.flipH, and that we--- can prove equality of the two functions.--rotate :: Picture -> Picture--rotate = flipH . flipV---- One picture above another. To maintain the rectangular property,--- the pictures need to have the same width.--above :: Picture -> Picture -> Picture--above = (++)---- One picture next to another. To maintain the rectangular property,--- the pictures need to have the same height.--beside :: Picture -> Picture -> Picture--beside = zipWith (++)---- Superimose one picture above another. Assume the pictures to be the same--- size. The individual characters are combined using the combine function.--superimpose :: Picture -> Picture -> Picture--superimpose = zipWith (zipWith combine)---- For the result to be '.' both components have to the '.'; otherwise--- get the '#' character.--combine :: Char -> Char -> Char--combine topCh bottomCh-  = if (topCh == '.' && bottomCh == '.') -    then '.'-    else '#'---- Inverting the colours in a picture; done pointwise by invert...--invertColour :: Picture -> Picture--invertColour = map (map invert)---- ... which works by making the result '.' unless the input is '.'.--invert :: Char -> Char--invert ch = if ch == '.' then '#' else '.'----- Property--prop_rotate, prop_flipV, prop_flipH :: Picture -> Bool--prop_rotate pic = flipV (flipH pic) == flipH (flipV pic)--prop_flipV pic = flipV (flipV pic) == pic--prop_flipH pic = flipH (flipV pic) == pic--test_rotate, test_flipV, test_flipH :: Bool- -test_rotate = flipV (flipH horse) == flipH (flipV horse)--test_flipV = flipV (flipV horse) == horse--test_flipH = flipH (flipV horse) == horse---- More properties--prop_AboveFlipV pic1 pic2 = -    flipV (pic1 `above` pic2) == (flipV pic1) `above` (flipV pic2) --prop_AboveFlipH pic1 pic2 = flipH (pic1 `above` pic2) == (flipH pic2) `above` (flipH pic1)--propAboveBeside1 nw ne sw se =-  (nw `beside` ne) `above` (sw `beside` se) -  == -  (nw `above` sw) `beside` (ne `above` se) --propAboveBeside2 n s =-  (n `beside` n) `above` (s `beside` s) == (n `above` s) `beside` (n `above` s) --propAboveBeside3 w e =-  (w `beside` e) `above` (w `beside` e) == (w `above` w) `beside` (e `above` e) --propAboveBeside3Correct w e =-  (rectangular w && rectangular e && height w == height e) -  ==>-     (w `beside` e) `above` (w `beside` e) -         == -     (w `above` w) `beside` (e `above` e) ---- auxiliary properties and functions--notEmpty pic = pic /= []--rectangular pic =-  notEmpty pic &&-  and [ length first == length l | l <-rest ]-  where-    (first:rest) = pic--height, width :: Picture -> Int--height = length-width = length . head--size :: Picture -> (Int,Int)--size pic = (width pic, height pic)--propAboveBesideFull nw ne sw se =-  (rectangular nw && rectangular ne && rectangular sw && rectangular se &&-   size nw == size ne && size ne == size se && size se == size sw) ==>-  (nw `beside` ne) `above` (sw `beside` se) == (nw `above` sw) `beside` (ne `above` se) ---- Using explicit generators ...---prop_1 = forAll (choose (1,10)) $ \x -> x/=x+(x::Int)--prop_2 = forAll (choose (1,10)) $ \x -> x/=(x::Int)---- Generators suited to Pictures---- chose either '.' or '#'--genChar :: Gen Char--genChar = oneof [return '.', return '#']---- generate a list of length n each element from generator g.--genList :: Int -> Gen a -> Gen [a]--genList n g = sequence [ g | i<-[1..n] ]---- generate a picture of given size using '.' and '#'--genSizedPicture :: Int -> Int -> Gen [String]--genSizedPicture height width =-      sequence [ genList width genChar | i<-[1::Int .. height] ]---- generate a picture of random size using '.' and '#'--genPicture :: Gen [String]--genPicture =-    do-      height <- choose (1,10)-      width  <- choose (1,10)-      genSizedPicture height width---- generate four pictures of the *same* random size using '.' and '#'--genFourPictures :: Gen ([String],[String],[String],[String])--genFourPictures =-    do-      height <- choose (1,10)-      width  <- choose (1,10)-      nw <- genSizedPicture height width-      ne <- genSizedPicture height width-      sw <- genSizedPicture height width-      se <- genSizedPicture height width-      return (nw,ne,sw,se)---- test that above and besides commute when used with four pictures--- of the same size--prop_AboveBeside =-    forAll genFourPictures $ \(nw,ne,sw,se) -> propAboveBeside1 nw ne sw se
− Chapter19/QC.hs
@@ -1,133 +0,0 @@------------------------------------------------------------------------------  Haskell: The Craft of Functional Programming---  Simon Thompson---  (c) Addison-Wesley, 1996-2011.--- ---  QC.hs------      Generating values randomly.-----------------------------------------------------------------------------module QC where--import Test.QuickCheck--import Control.Monad (liftM,liftM2)-import System.IO.Unsafe (unsafePerformIO)-import Data.List (nub)-import QCfuns -- to Show functions---- Simple examples for data generation--data Card = Card Int String-            deriving (Eq,Show)--data Info = Number Int | Email String-            deriving (Eq, Show)--data List a = Empty | Cons a (List a)-            deriving (Eq, Show)--instance Arbitrary Card where-    arbitrary =-        do-          int <- arbitrary-          string <- arbitrary-          return (Card int string)--instance Arbitrary Info where-    arbitrary =-        do-          boo <- arbitrary-          if boo-            then do-              int <- arbitrary-              return (Number int) -            else do-              string <- arbitrary-              return (Email string) ---- Generating lists of samples---- instance Arbitrary a => Arbitrary (List a) where---     arbitrary =---         do---           boo <- elements [True, False]---           if boo---                   then ---                     return $ Empty ---                   else do---                     val  <- arbitrary---                     list <- arbitrary---                     return $ Cons val list --instance Arbitrary a => Arbitrary (List a) where-    arbitrary =-        do-          switch <- elements [1,2,3]-          case switch of -            1 -> return Empty -            _ -> -                do-                  val  <- arbitrary-                  list <- arbitrary-                  return (Cons val list) ---- The expr type from the calculator--data Expr = Lit Integer |-            Add Expr Expr |-            Sub Expr Expr-                deriving (Show,Eq)--instance Arbitrary Expr where-    arbitrary = sized arbExpr--arbExpr :: Int -> Gen Expr--arbExpr 0 = liftM Lit arbitrary--arbExpr n = frequency-    [(1, liftM Lit arbitrary),-     (2, liftM2 Add subExp subExp),-     (2, liftM2 Sub subExp subExp)]-        where-          subExp = arbExpr (div n 2)-{--arbExpr 0 = -    do int <- arbitrary-       return (Lit int)--arbExpr n-    | n>0 =-        do-          pick <- choose (0,2::Int)-          case pick of-            0 -> do -              int <- arbitrary-              return (Lit int)-            1 -> do -              left  <- subExp-              right <- subExp-              return (Add left right)-            2 -> do -              left  <- subExp-              right <- subExp-              return (Sub left right)-        where-          subExp = arbExpr (div n 2)--}--prettyE :: Expr -> String--prettyE (Lit n) = show n-prettyE (Add e1 e2) = "("++prettyE e1 ++"+"++prettyE e2 ++")"-prettyE (Sub e1 e2) = "("++prettyE e1 ++"-"++prettyE e2 ++")"---- Property of map--prop_map f g xs =-  map (f::Int->Int) (map (g::Int -> Int) xs) == map (g.f) xs-
− Chapter19/QCfuns.hs
@@ -1,37 +0,0 @@--------------------------------------------------------------------------------  Haskell: The Craft of Functional Programming---  Simon Thompson---  (c) Addison-Wesley, 1996-2011.------  QCfuns-------------------------------------------------------------------------------module QCfuns where--import Test.QuickCheck-import System.IO.Unsafe -- for unsafePerformIO---- Sampling and showing functions--sampleFun :: (Arbitrary a,Show a, Show b)  => (a -> b) -> IO String--sampleFun f =-    do-      inputs <- sample' arbitrary-      let list = [ (a,f a) | a <- inputs ]-      return $ showMap list--showMap :: (Show a, Show b) => [(a,b)] -> String--showMap [] = "\n"-showMap [(a,b)] = showPair (a,b) ++ "\n"-showMap (p:ps)  = showPair p ++ " ," ++ showMap ps--showPair :: (Show a, Show b) => (a,b) -> String--showPair (a,b) = "("++show a ++ "|->" ++ show b ++ ")"--instance (Arbitrary a, Show a, Show b) => Show (a -> b) where-    show = unsafePerformIO . sampleFun
− Chapter19/RegExp.hs
@@ -1,133 +0,0 @@------------------------------------------------------------------------------  Haskell: The Craft of Functional Programming---  Simon Thompson---  (c) Addison-Wesley, 1996-2011.------      RegExp.hs--- ---  Regular Expressions-----------------------------------------------------------------------------module RegExp where--type RegExp = String -> Bool--char :: Char -> RegExp--epsilon = (=="")--char ch = (==[ch])--(|||) :: RegExp -> RegExp ->  RegExp--e1 ||| e2 = -    \x -> e1 x || e2 x--(<*>) :: RegExp -> RegExp ->  RegExp--e1 <*> e2 =-    \x -> or [ e1 y && e2 z | (y,z) <- splits x ]--(<**>) :: RegExp -> RegExp ->  RegExp--e1 <**> e2 =-    \x -> or [ e1 y && e2 z | (y,z) <- fsplits x ]--splits xs = [splitAt n xs | n<-[0..len]]-    where-      len = length xs--star :: RegExp -> RegExp--star p = epsilon ||| (p <**> star p)---           epsilon ||| (p <*> star p)--- is OK as long as p can't have epsilon match--fsplits xs = tail (splits xs)---- a = char 'a'---- b = char 'b'--infixr 7 :*:-infixr 5 :|:--data RE = Eps |-          Ch Char |-          RE :|: RE |-          RE :*: RE |-          St RE |-          Plus RE-          deriving(Eq,Show)--evens = St two-two = (a :|: b) :*: (a :|: b)-          -a = Ch 'a'-b = Ch 'b'---- interp: RE -> RegExp: exercise.---- Value recursion---  Eunmerating strings matching a regexp--enumerate :: RE -> [String]--enumerate Eps = [""]-enumerate (Ch ch) = [[ch]]-enumerate (re1 :|: re2)-    = enumerate re1 `interleave` enumerate re2-enumerate  (re1 :*: re2)-    = enumerate re1 `cartesian` enumerate re2-enumerate (St re)-    = result -      where-        result =-            [""] ++ (enumerate re `cartesian` result)---- Auxiliary functions--- interleave and product for potentially infinite lists--interleave :: [a] -> [a] -> [a]--interleave [] ys = ys-interleave (x:xs) ys = x : interleave ys xs-        -cartesian :: [[a]] -> [[a]] -> [[a]]--cartesian [] ys = []-cartesian (x:xs) ys -    = [ x++y | y<-ys ] `interleave` cartesian xs ys-    --- Recursive regular expressions--anbn :: RE--anbn = Eps :|: (a :*: (anbn :*: b))---- Extending the implementation--plus :: RE -> RE-plus re = re :*: St re---- Simplification--simplify :: RE -> RE--simplify (St (St re)) = simplify (St re)-simplify (Plus (St re)) = simplify (St re)-simplify (St (Plus re)) = simplify (St re)-simplify (re1 :|: re2) =-    if sre1==sre2 then sre1 else sre1 :|: sre2 -          where-            sre1 = simplify re1; sre2 = simplify re2-simplify re = re---- smart constructors--starC :: RE -> RE-starC (St re) = re-starC (Plus re) = re-starC re = St re
− Chapter20/Chapter20.hs
@@ -1,237 +0,0 @@----  Haskell: The Craft of Functional Programming---  Simon Thompson---  (c) Addison-Wesley, 1996-2010.----  Chapter 20---- Time and space behaviour--- ^^^^^^^^^^^^^^^^^^^^^^^^--module Chapter20 where--import Prelude hiding (map)---- Various functions whose complexity is discussed.--- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---- Naive Fibonacci function--fib :: Integer -> Integer--fib 0 = 0-fib 1 = 1-fib m = fib (m-2) + fib (m-1)---- Naive factorial function--fac :: Integer -> Integer-fac 0 = 1-fac n = n * fac (n-1)---- Insertion sort--iSort :: Ord a => [a] -> [a]--iSort []     = []-iSort (x:xs) = ins x (iSort xs)--ins :: Ord a => a -> [a] -> [a]--ins x [] = [x]-ins x (y:ys) -  | (x<=y)      = x:y:ys-  | otherwise   = y:ins x ys---- Quicksort--qSort :: Ord a => [a] -> [a]--qSort []     = []-qSort (x:xs) = qSort [z|z<-xs,z<=x] ++ [x] ++ qSort [z|z<-xs,z>x]---- Two reverse functions--rev1 []     = []-rev1 (x:xs) = rev1 xs ++ [x]--rev2            = shunt []-shunt xs []     = xs-shunt xs (y:ys) = shunt (y:xs) ys---- Two multiplication functions--mult n 0 = 0-mult n m = mult n (m-1) + n--russ n 0 = 0-russ n m -  | (m `mod` 2 == 0)    = russ (n+n) (m `div` 2)-  | otherwise           = russ (n+n) (m `div` 2) + n---- The merge sort function --mSort :: Ord a => [a] -> [a]--mSort xs -  | (len < 2)   = xs-  | otherwise   = mer (mSort (take m xs)) (mSort (drop m xs))-    where-    len = length xs-    m   = len `div` 2--mer :: Ord a => [a] -> [a]  -> [a]--mer (x:xs) (y:ys) -  | (x<=y)      = x : mer xs (y:ys)-  | otherwise   = y : mer (x:xs) ys-mer (x:xs) []   = (x:xs)-mer []     ys   = ys---- Implementations of sets--- ^^^^^^^^^^^^^^^^^^^^^^^---- Sets implemented as _unordered_ lists.---- type Set a = [a]---- empty        = []--- memSet       = member--- inter xs ys  = filter (member xs) ys--- union        = (++)--- subSet xs ys = and (map (member ys) xs)--- eqSet xs ys  = subSet xs ys && subSet ys xs--- makeSet      = id--- mapSet       = map---  ----- Space behaviour--- ^^^^^^^^^^^^^^^---- Lazy evaluation--- ^^^^^^^^^^^^^^^---- List examples--exam1 n = [1 .. n] ++ [1 .. n]--exam2 n = list ++ list -          where -          list=[1 .. n]--exam3 n = [1 .. n] ++ [last [1 .. n]]--exam4 n = list ++ [last list]-          where-          list=[1 .. n]----- Saving space?--- ^^^^^^^^^^^^^---- A new version of factorial--newFac :: Integer -> Integer-newFac n = aFac n 1--aFac :: Integer -> Integer -> Integer-aFac 0 p = p-aFac n p = aFac (n-1) (p*n)---- This can be modified thus:---  aFac n p---    | p==p        = aFac (n-1) (p*n)---- Miscellaneous functions--sumSquares :: Integer -> Integer-sumSquares n = sumList (map sq [1 .. n])--sumList = foldr (+) 0-sq n    = n*n------ Folding revisited--- ^^^^^^^^^^^^^^^^^---- Map defined using foldr--map f = foldr ((:).f) []---- Factorial using foldr--facFold n = foldr (*) 1 [1 .. n]---- Examples--foldEx1 n = foldr (&&) True (map (==2) [2 .. n])------ Avoiding re-computation: memoization--- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---- The Fibonacci numbers---- A naive algorithm is given earlier in this script.---- An algorithm which returns a pair of consecutive Fibonacci numbers.--fibP :: Integer -> (Integer,Integer)--fibP 0 = (0,1)-fibP n = (y,x+y)-         where-         (x,y) = fibP (n-1)---- The list of Fibonacci values, defined directly.--fibs ::[Integer]--fibs = 0 : 1 : zipWith (+) fibs (tail fibs)----- Dynamic programming: maximal common subsequence--- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---- The naive algorithm ...--mLen :: Eq a => [a] -> [a] -> Integer--mLen xs []        = 0-mLen [] ys        = 0-mLen (x:xs) (y:ys) -  | x==y        = 1 + mLen xs ys-  | otherwise   = max (mLen xs (y:ys)) (mLen (x:xs) ys)---- ... translated to talk about sub-components of lists, described by their--- endpoints ...--maxLen :: Eq a => [a] -> [a] -> Int -> Int -> Int--maxLen xs ys 0 j = 0 -maxLen xs ys i 0 = 0-maxLen xs ys i j-  | xs!!(i-1) == ys!!(j-1)  = (maxLen xs ys (i-1) (j-1)) + 1-  | otherwise               = max (maxLen xs ys i (j-1))-                                  (maxLen xs ys (i-1) j)---- ... and then transliterated into a memoised version.--maxTab ::  Eq a => [a] -> [a] -> [[Int]]--maxTab xs ys-  = result-    where -    result = [0,0 .. ] : zipWith f [0 .. ] result-    f i prev  -        = ans-          where-          ans   = 0 : zipWith g [0 .. ] ans-          g j v -            | xs!!i == ys!!j      = prev!!j + 1-            | otherwise           = max v (prev!!(j+1))--
− Chapter20/PerformanceI.hs
@@ -1,37 +0,0 @@------------------------------------------------------------------------------  Haskell: The Craft of Functional Programming---  Simon Thompson---  (c) Addison-Wesley, 1996-2011.------  PerformanceI.hs-----------------------------------------------------------------------------module Main where--main = putStrLn (show (sumI 1 1000000))--- main = putStrLn (show (sumIA 1 1000000))--- main = putStrLn (show (sumIS 1 1000000))--sumI :: Integer -> Integer -> Integer--sumI n m- | n>m       = 0- | otherwise = n + sumI (n+1) m--sumIA :: Integer -> Integer -> Integer--sumIA n m = accIA n m 0--accIA n m s- | n>m       = s- | otherwise = accIA (n+1) m (n+s)--sumIS :: Integer -> Integer -> Integer--sumIS n m = accIS n m 0--accIS n m s- | n>m       = s- | otherwise = accIS (n+1) m $! (n+s)
− Chapter20/PerformanceIA.hs
@@ -1,37 +0,0 @@------------------------------------------------------------------------------  Haskell: The Craft of Functional Programming---  Simon Thompson---  (c) Addison-Wesley, 1996-2011.------  PerformanceIA.hs-----------------------------------------------------------------------------module Main where---- main = putStrLn (show (sumI 1 1000000))-main = putStrLn (show (sumIA 1 1000000))---- main = putStrLn (show (sumIS 1 1000000))--sumI :: Integer -> Integer -> Integer--sumI n m- | n>m       = 0- | otherwise = n + sumI (n+1) m--sumIA :: Integer -> Integer -> Integer--sumIA n m = accIA n m 0--accIA n m s- | n>m       = s- | otherwise = accIA (n+1) m (n+s)--sumIS :: Integer -> Integer -> Integer--sumIS n m = accIS n m 0--accIS n m s- | n>m       = s- | otherwise = accIS (n+1) m $! (n+s)
− Chapter20/PerformanceIS.hs
@@ -1,37 +0,0 @@------------------------------------------------------------------------------  Haskell: The Craft of Functional Programming---  Simon Thompson---  (c) Addison-Wesley, 1996-2011.------  PerformanceIS.hs-----------------------------------------------------------------------------module Main where---- main = putStrLn (show (sumI 1 1000000))--- main = putStrLn (show (sumIA 1 1000000))-main = putStrLn (show (sumIS 1 1000000))--sumI :: Integer -> Integer -> Integer--sumI n m- | n>m       = 0- | otherwise = n + sumI (n+1) m--sumIA :: Integer -> Integer -> Integer--sumIA n m = accIA n m 0--accIA n m s- | n>m       = s- | otherwise = accIA (n+1) m (n+s)--sumIS :: Integer -> Integer -> Integer--sumIS n m = accIS n m 0--accIS n m s- | n>m       = s- | otherwise = accIS (n+1) m $! (n+s)
+ Chapter20/Pic.hs view
@@ -0,0 +1,63 @@+-----------------------------------------------------------------------+--+--  Haskell: The Craft of Functional Programming+--  Simon Thompson+--  (c) Addison-Wesley, 1996-2011.+--+--  Pic.hs+-- +--      A deep embedding of pictures+--+-----------------------------------------------------------------------++module Pic where++import Pictures++-- Data type representing pictures++data Pic = Horse |+           Above Pic Pic |+           Beside Pic Pic |+           FlipH Pic |+           FlipV Pic ++-- Interpreting a Pic as a Picture++interpretPic :: Pic -> Picture++interpretPic Horse = horse+interpretPic (Above pic1 pic2)+  = above (interpretPic pic1)  (interpretPic pic2)+interpretPic (Beside pic1 pic2)+  = beside (interpretPic pic1)  (interpretPic pic2)+interpretPic (FlipH pic)+  = flipH (interpretPic pic)+interpretPic (FlipV pic)+  = flipV (interpretPic pic)++-- Tidying up a picture ...++-- remove pairs of flips+-- push flips through placement above / beside++tidyPic :: Pic -> Pic++tidyPic (FlipV (FlipV pic)) +  = tidyPic pic+tidyPic (FlipV (FlipH pic)) +  = FlipH (tidyPic (FlipV pic)) ++tidyPic (FlipV (Above pic1 pic2))+  = Above (tidyPic (FlipV pic1)) (tidyPic (FlipV pic2)) +tidyPic (FlipV (Beside pic1 pic2))+  = Beside (tidyPic (FlipV pic2)) (tidyPic (FlipV pic1)) ++tidyPic (FlipH (FlipH pic)) +  = tidyPic pic+  +tidyPic (FlipH (Above pic1 pic2))+  = Above (tidyPic (FlipH pic2)) (tidyPic (FlipH pic1)) +tidyPic (FlipH (Beside pic1 pic2))+  = Beside (tidyPic (FlipH pic1)) (tidyPic (FlipH pic2)) +  
+ Chapter20/Pictures.hs view
@@ -0,0 +1,256 @@+-----------------------------------------------------------------------+--  Haskell: The Craft of Functional Programming+--  Simon Thompson+--  (c) Addison-Wesley, 1996-2010.+--+--  Pictures.hs+-- +--     An implementation of a type of rectangular pictures  +--     using lists of lists of characters. +-----------------------------------------------------------------------++++-- The basics+-- ^^^^^^^^^^++module Pictures where+import Test.QuickCheck+++type Picture = [[Char]]++-- The example used in Craft2e: a polygon which looks like a horse. Here+-- taken to be a 16 by 12 rectangle.++horse :: Picture++horse = [".......##...",+         ".....##..#..",+         "...##.....#.",+         "..#.......#.",+         "..#...#...#.",+         "..#...###.#.",+         ".#....#..##.",+         "..#...#.....",+         "...#...#....",+         "....#..#....",+         ".....#.#....",+         "......##...."]++-- Completely white and black pictures.++white :: Picture++white = ["......",+         "......",+         "......",+         "......",+         "......",+         "......"]++black = ["######",+         "######",+         "######",+         "######",+         "######",+         "######"]++-- Getting a picture onto the screen.++printPicture :: Picture -> IO ()++printPicture = putStr . concat . map (++"\n")+++-- Transformations of pictures.+-- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^++-- Reflection in a vertical mirror.++flipV :: Picture -> Picture++flipV = map reverse++-- Reflection in a horizontal mirror.++flipH :: Picture -> Picture++flipH = reverse++-- Rotation through 180 degrees, by composing vertical and horizontal+-- reflection. Note that it can also be done by flipV.flipH, and that we+-- can prove equality of the two functions.++rotate :: Picture -> Picture++rotate = flipH . flipV++-- One picture above another. To maintain the rectangular property,+-- the pictures need to have the same width.++above :: Picture -> Picture -> Picture++above = (++)++-- One picture next to another. To maintain the rectangular property,+-- the pictures need to have the same height.++beside :: Picture -> Picture -> Picture++beside = zipWith (++)++-- Superimose one picture above another. Assume the pictures to be the same+-- size. The individual characters are combined using the combine function.++superimpose :: Picture -> Picture -> Picture++superimpose = zipWith (zipWith combine)++-- For the result to be '.' both components have to the '.'; otherwise+-- get the '#' character.++combine :: Char -> Char -> Char++combine topCh bottomCh+  = if (topCh == '.' && bottomCh == '.') +    then '.'+    else '#'++-- Inverting the colours in a picture; done pointwise by invert...++invertColour :: Picture -> Picture++invertColour = map (map invert)++-- ... which works by making the result '.' unless the input is '.'.++invert :: Char -> Char++invert ch = if ch == '.' then '#' else '.'+++-- Property++prop_rotate, prop_flipV, prop_flipH :: Picture -> Bool++prop_rotate pic = flipV (flipH pic) == flipH (flipV pic)++prop_flipV pic = flipV (flipV pic) == pic++prop_flipH pic = flipH (flipV pic) == pic++test_rotate, test_flipV, test_flipH :: Bool+ +test_rotate = flipV (flipH horse) == flipH (flipV horse)++test_flipV = flipV (flipV horse) == horse++test_flipH = flipH (flipV horse) == horse++-- More properties++prop_AboveFlipV pic1 pic2 = +    flipV (pic1 `above` pic2) == (flipV pic1) `above` (flipV pic2) ++prop_AboveFlipH pic1 pic2 = flipH (pic1 `above` pic2) == (flipH pic2) `above` (flipH pic1)++propAboveBeside1 nw ne sw se =+  (nw `beside` ne) `above` (sw `beside` se) +  == +  (nw `above` sw) `beside` (ne `above` se) ++propAboveBeside2 n s =+  (n `beside` n) `above` (s `beside` s) == (n `above` s) `beside` (n `above` s) ++propAboveBeside3 w e =+  (w `beside` e) `above` (w `beside` e) == (w `above` w) `beside` (e `above` e) ++propAboveBeside3Correct w e =+  (rectangular w && rectangular e && height w == height e) +  ==>+     (w `beside` e) `above` (w `beside` e) +         == +     (w `above` w) `beside` (e `above` e) ++-- auxiliary properties and functions++notEmpty pic = pic /= []++rectangular pic =+  notEmpty pic &&+  and [ length first == length l | l <-rest ]+  where+    (first:rest) = pic++height, width :: Picture -> Int++height = length+width = length . head++size :: Picture -> (Int,Int)++size pic = (width pic, height pic)++propAboveBesideFull nw ne sw se =+  (rectangular nw && rectangular ne && rectangular sw && rectangular se &&+   size nw == size ne && size ne == size se && size se == size sw) ==>+  (nw `beside` ne) `above` (sw `beside` se) == (nw `above` sw) `beside` (ne `above` se) ++-- Using explicit generators ...+++prop_1 = forAll (choose (1,10)) $ \x -> x/=x+(x::Int)++prop_2 = forAll (choose (1,10)) $ \x -> x/=(x::Int)++-- Generators suited to Pictures++-- chose either '.' or '#'++genChar :: Gen Char++genChar = oneof [return '.', return '#']++-- generate a list of length n each element from generator g.++genList :: Int -> Gen a -> Gen [a]++genList n g = sequence [ g | i<-[1..n] ]++-- generate a picture of given size using '.' and '#'++genSizedPicture :: Int -> Int -> Gen [String]++genSizedPicture height width =+      sequence [ genList width genChar | i<-[1::Int .. height] ]++-- generate a picture of random size using '.' and '#'++genPicture :: Gen [String]++genPicture =+    do+      height <- choose (1,10)+      width  <- choose (1,10)+      genSizedPicture height width++-- generate four pictures of the *same* random size using '.' and '#'++genFourPictures :: Gen ([String],[String],[String],[String])++genFourPictures =+    do+      height <- choose (1,10)+      width  <- choose (1,10)+      nw <- genSizedPicture height width+      ne <- genSizedPicture height width+      sw <- genSizedPicture height width+      se <- genSizedPicture height width+      return (nw,ne,sw,se)++-- test that above and besides commute when used with four pictures+-- of the same size++prop_AboveBeside =+    forAll genFourPictures $ \(nw,ne,sw,se) -> propAboveBeside1 nw ne sw se
+ Chapter20/QC.hs view
@@ -0,0 +1,133 @@+-----------------------------------------------------------------------+--+--  Haskell: The Craft of Functional Programming+--  Simon Thompson+--  (c) Addison-Wesley, 1996-2011.+-- +--  QC.hs+--+--      Generating values randomly.+--+-----------------------------------------------------------------------++module QC where++import Test.QuickCheck++import Control.Monad (liftM,liftM2)+import System.IO.Unsafe (unsafePerformIO)+import Data.List (nub)+import QCfuns -- to Show functions++-- Simple examples for data generation++data Card = Card Int String+            deriving (Eq,Show)++data Info = Number Int | Email String+            deriving (Eq, Show)++data List a = Empty | Cons a (List a)+            deriving (Eq, Show)++instance Arbitrary Card where+    arbitrary =+        do+          int <- arbitrary+          string <- arbitrary+          return (Card int string)++instance Arbitrary Info where+    arbitrary =+        do+          boo <- arbitrary+          if boo+            then do+              int <- arbitrary+              return (Number int) +            else do+              string <- arbitrary+              return (Email string) ++-- Generating lists of samples++-- instance Arbitrary a => Arbitrary (List a) where+--     arbitrary =+--         do+--           boo <- elements [True, False]+--           if boo+--                   then +--                     return $ Empty +--                   else do+--                     val  <- arbitrary+--                     list <- arbitrary+--                     return $ Cons val list ++instance Arbitrary a => Arbitrary (List a) where+    arbitrary =+        do+          switch <- elements [1,2,3]+          case switch of +            1 -> return Empty +            _ -> +                do+                  val  <- arbitrary+                  list <- arbitrary+                  return (Cons val list) ++-- The expr type from the calculator++data Expr = Lit Integer |+            Add Expr Expr |+            Sub Expr Expr+                deriving (Show,Eq)++instance Arbitrary Expr where+    arbitrary = sized arbExpr++arbExpr :: Int -> Gen Expr++arbExpr 0 = liftM Lit arbitrary++arbExpr n = frequency+    [(1, liftM Lit arbitrary),+     (2, liftM2 Add subExp subExp),+     (2, liftM2 Sub subExp subExp)]+        where+          subExp = arbExpr (div n 2)+{-+arbExpr 0 = +    do int <- arbitrary+       return (Lit int)++arbExpr n+    | n>0 =+        do+          pick <- choose (0,2::Int)+          case pick of+            0 -> do +              int <- arbitrary+              return (Lit int)+            1 -> do +              left  <- subExp+              right <- subExp+              return (Add left right)+            2 -> do +              left  <- subExp+              right <- subExp+              return (Sub left right)+        where+          subExp = arbExpr (div n 2)+-}++prettyE :: Expr -> String++prettyE (Lit n) = show n+prettyE (Add e1 e2) = "("++prettyE e1 ++"+"++prettyE e2 ++")"+prettyE (Sub e1 e2) = "("++prettyE e1 ++"-"++prettyE e2 ++")"++-- Property of map++prop_map f g xs =+  map (f::Int->Int) (map (g::Int -> Int) xs) == map (g.f) xs+
+ Chapter20/QCfuns.hs view
@@ -0,0 +1,37 @@+-------------------------------------------------------------------------+--+--  Haskell: The Craft of Functional Programming+--  Simon Thompson+--  (c) Addison-Wesley, 1996-2011.+--+--  QCfuns+--+-------------------------------------------------------------------------++module QCfuns where++import Test.QuickCheck+import System.IO.Unsafe -- for unsafePerformIO++-- Sampling and showing functions++sampleFun :: (Arbitrary a,Show a, Show b)  => (a -> b) -> IO String++sampleFun f =+    do+      inputs <- sample' arbitrary+      let list = [ (a,f a) | a <- inputs ]+      return $ showMap list++showMap :: (Show a, Show b) => [(a,b)] -> String++showMap [] = "\n"+showMap [(a,b)] = showPair (a,b) ++ "\n"+showMap (p:ps)  = showPair p ++ " ," ++ showMap ps++showPair :: (Show a, Show b) => (a,b) -> String++showPair (a,b) = "("++show a ++ "|->" ++ show b ++ ")"++instance (Arbitrary a, Show a, Show b) => Show (a -> b) where+    show = unsafePerformIO . sampleFun
+ Chapter20/RegExp.hs view
@@ -0,0 +1,133 @@+-----------------------------------------------------------------------+--+--  Haskell: The Craft of Functional Programming+--  Simon Thompson+--  (c) Addison-Wesley, 1996-2011.+--+--      RegExp.hs+-- +--  Regular Expressions+--+-----------------------------------------------------------------------++module RegExp where++type RegExp = String -> Bool++char :: Char -> RegExp++epsilon = (=="")++char ch = (==[ch])++(|||) :: RegExp -> RegExp ->  RegExp++e1 ||| e2 = +    \x -> e1 x || e2 x++(<*>) :: RegExp -> RegExp ->  RegExp++e1 <*> e2 =+    \x -> or [ e1 y && e2 z | (y,z) <- splits x ]++(<**>) :: RegExp -> RegExp ->  RegExp++e1 <**> e2 =+    \x -> or [ e1 y && e2 z | (y,z) <- fsplits x ]++splits xs = [splitAt n xs | n<-[0..len]]+    where+      len = length xs++star :: RegExp -> RegExp++star p = epsilon ||| (p <**> star p)+--           epsilon ||| (p <*> star p)+-- is OK as long as p can't have epsilon match++fsplits xs = tail (splits xs)++-- a = char 'a'++-- b = char 'b'++infixr 7 :*:+infixr 5 :|:++data RE = Eps |+          Ch Char |+          RE :|: RE |+          RE :*: RE |+          St RE |+          Plus RE+          deriving(Eq,Show)++evens = St two+two = (a :|: b) :*: (a :|: b)+          +a = Ch 'a'+b = Ch 'b'++-- interp: RE -> RegExp: exercise.++-- Value recursion+--  Eunmerating strings matching a regexp++enumerate :: RE -> [String]++enumerate Eps = [""]+enumerate (Ch ch) = [[ch]]+enumerate (re1 :|: re2)+    = enumerate re1 `interleave` enumerate re2+enumerate  (re1 :*: re2)+    = enumerate re1 `cartesian` enumerate re2+enumerate (St re)+    = result +      where+        result =+            [""] ++ (enumerate re `cartesian` result)++-- Auxiliary functions+-- interleave and product for potentially infinite lists++interleave :: [a] -> [a] -> [a]++interleave [] ys = ys+interleave (x:xs) ys = x : interleave ys xs+        +cartesian :: [[a]] -> [[a]] -> [[a]]++cartesian [] ys = []+cartesian (x:xs) ys +    = [ x++y | y<-ys ] `interleave` cartesian xs ys+    +-- Recursive regular expressions++anbn :: RE++anbn = Eps :|: (a :*: (anbn :*: b))++-- Extending the implementation++plus :: RE -> RE+plus re = re :*: St re++-- Simplification++simplify :: RE -> RE++simplify (St (St re)) = simplify (St re)+simplify (Plus (St re)) = simplify (St re)+simplify (St (Plus re)) = simplify (St re)+simplify (re1 :|: re2) =+    if sre1==sre2 then sre1 else sre1 :|: sre2 +          where+            sre1 = simplify re1; sre2 = simplify re2+simplify re = re++-- smart constructors++starC :: RE -> RE+starC (St re) = re+starC (Plus re) = re+starC re = St re
+ Chapter21/Chapter21.hs view
@@ -0,0 +1,237 @@++--  Haskell: The Craft of Functional Programming+--  Simon Thompson+--  (c) Addison-Wesley, 1996-2010.++--  Chapter 21++-- Time and space behaviour+-- ^^^^^^^^^^^^^^^^^^^^^^^^++module Chapter21 where++import Prelude hiding (map)++-- Various functions whose complexity is discussed.+-- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^++-- Naive Fibonacci function++fib :: Integer -> Integer++fib 0 = 0+fib 1 = 1+fib m = fib (m-2) + fib (m-1)++-- Naive factorial function++fac :: Integer -> Integer+fac 0 = 1+fac n = n * fac (n-1)++-- Insertion sort++iSort :: Ord a => [a] -> [a]++iSort []     = []+iSort (x:xs) = ins x (iSort xs)++ins :: Ord a => a -> [a] -> [a]++ins x [] = [x]+ins x (y:ys) +  | (x<=y)      = x:y:ys+  | otherwise   = y:ins x ys++-- Quicksort++qSort :: Ord a => [a] -> [a]++qSort []     = []+qSort (x:xs) = qSort [z|z<-xs,z<=x] ++ [x] ++ qSort [z|z<-xs,z>x]++-- Two reverse functions++rev1 []     = []+rev1 (x:xs) = rev1 xs ++ [x]++rev2            = shunt []+shunt xs []     = xs+shunt xs (y:ys) = shunt (y:xs) ys++-- Two multiplication functions++mult n 0 = 0+mult n m = mult n (m-1) + n++russ n 0 = 0+russ n m +  | (m `mod` 2 == 0)    = russ (n+n) (m `div` 2)+  | otherwise           = russ (n+n) (m `div` 2) + n++-- The merge sort function ++mSort :: Ord a => [a] -> [a]++mSort xs +  | (len < 2)   = xs+  | otherwise   = mer (mSort (take m xs)) (mSort (drop m xs))+    where+    len = length xs+    m   = len `div` 2++mer :: Ord a => [a] -> [a]  -> [a]++mer (x:xs) (y:ys) +  | (x<=y)      = x : mer xs (y:ys)+  | otherwise   = y : mer (x:xs) ys+mer (x:xs) []   = (x:xs)+mer []     ys   = ys++-- Implementations of sets+-- ^^^^^^^^^^^^^^^^^^^^^^^++-- Sets implemented as _unordered_ lists.++-- type Set a = [a]++-- empty        = []+-- memSet       = member+-- inter xs ys  = filter (member xs) ys+-- union        = (++)+-- subSet xs ys = and (map (member ys) xs)+-- eqSet xs ys  = subSet xs ys && subSet ys xs+-- makeSet      = id+-- mapSet       = map+--  +++-- Space behaviour+-- ^^^^^^^^^^^^^^^++-- Lazy evaluation+-- ^^^^^^^^^^^^^^^++-- List examples++exam1 n = [1 .. n] ++ [1 .. n]++exam2 n = list ++ list +          where +          list=[1 .. n]++exam3 n = [1 .. n] ++ [last [1 .. n]]++exam4 n = list ++ [last list]+          where+          list=[1 .. n]+++-- Saving space?+-- ^^^^^^^^^^^^^++-- A new version of factorial++newFac :: Integer -> Integer+newFac n = aFac n 1++aFac :: Integer -> Integer -> Integer+aFac 0 p = p+aFac n p = aFac (n-1) (p*n)++-- This can be modified thus:+--  aFac n p+--    | p==p        = aFac (n-1) (p*n)++-- Miscellaneous functions++sumSquares :: Integer -> Integer+sumSquares n = sumList (map sq [1 .. n])++sumList = foldr (+) 0+sq n    = n*n++++-- Folding revisited+-- ^^^^^^^^^^^^^^^^^++-- Map defined using foldr++map f = foldr ((:).f) []++-- Factorial using foldr++facFold n = foldr (*) 1 [1 .. n]++-- Examples++foldEx1 n = foldr (&&) True (map (==2) [2 .. n])++++-- Avoiding re-computation: memoization+-- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^++-- The Fibonacci numbers++-- A naive algorithm is given earlier in this script.++-- An algorithm which returns a pair of consecutive Fibonacci numbers.++fibP :: Integer -> (Integer,Integer)++fibP 0 = (0,1)+fibP n = (y,x+y)+         where+         (x,y) = fibP (n-1)++-- The list of Fibonacci values, defined directly.++fibs ::[Integer]++fibs = 0 : 1 : zipWith (+) fibs (tail fibs)+++-- Dynamic programming: maximal common subsequence+-- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^++-- The naive algorithm ...++mLen :: Eq a => [a] -> [a] -> Integer++mLen xs []        = 0+mLen [] ys        = 0+mLen (x:xs) (y:ys) +  | x==y        = 1 + mLen xs ys+  | otherwise   = max (mLen xs (y:ys)) (mLen (x:xs) ys)++-- ... translated to talk about sub-components of lists, described by their+-- endpoints ...++maxLen :: Eq a => [a] -> [a] -> Int -> Int -> Int++maxLen xs ys 0 j = 0 +maxLen xs ys i 0 = 0+maxLen xs ys i j+  | xs!!(i-1) == ys!!(j-1)  = (maxLen xs ys (i-1) (j-1)) + 1+  | otherwise               = max (maxLen xs ys i (j-1))+                                  (maxLen xs ys (i-1) j)++-- ... and then transliterated into a memoised version.++maxTab ::  Eq a => [a] -> [a] -> [[Int]]++maxTab xs ys+  = result+    where +    result = [0,0 .. ] : zipWith f [0 .. ] result+    f i prev  +        = ans+          where+          ans   = 0 : zipWith g [0 .. ] ans+          g j v +            | xs!!i == ys!!j      = prev!!j + 1+            | otherwise           = max v (prev!!(j+1))++
+ Chapter21/PerformanceI.hs view
@@ -0,0 +1,37 @@+-----------------------------------------------------------------------+--+--  Haskell: The Craft of Functional Programming+--  Simon Thompson+--  (c) Addison-Wesley, 1996-2011.+--+--  PerformanceI.hs+--+-----------------------------------------------------------------------++module Main where++main = putStrLn (show (sumI 1 1000000))+-- main = putStrLn (show (sumIA 1 1000000))+-- main = putStrLn (show (sumIS 1 1000000))++sumI :: Integer -> Integer -> Integer++sumI n m+ | n>m       = 0+ | otherwise = n + sumI (n+1) m++sumIA :: Integer -> Integer -> Integer++sumIA n m = accIA n m 0++accIA n m s+ | n>m       = s+ | otherwise = accIA (n+1) m (n+s)++sumIS :: Integer -> Integer -> Integer++sumIS n m = accIS n m 0++accIS n m s+ | n>m       = s+ | otherwise = accIS (n+1) m $! (n+s)
+ Chapter21/PerformanceIA.hs view
@@ -0,0 +1,37 @@+-----------------------------------------------------------------------+--+--  Haskell: The Craft of Functional Programming+--  Simon Thompson+--  (c) Addison-Wesley, 1996-2011.+--+--  PerformanceIA.hs+--+-----------------------------------------------------------------------++module Main where++-- main = putStrLn (show (sumI 1 1000000))+main = putStrLn (show (sumIA 1 1000000))+--- main = putStrLn (show (sumIS 1 1000000))++sumI :: Integer -> Integer -> Integer++sumI n m+ | n>m       = 0+ | otherwise = n + sumI (n+1) m++sumIA :: Integer -> Integer -> Integer++sumIA n m = accIA n m 0++accIA n m s+ | n>m       = s+ | otherwise = accIA (n+1) m (n+s)++sumIS :: Integer -> Integer -> Integer++sumIS n m = accIS n m 0++accIS n m s+ | n>m       = s+ | otherwise = accIS (n+1) m $! (n+s)
+ Chapter21/PerformanceIS.hs view
@@ -0,0 +1,37 @@+-----------------------------------------------------------------------+--+--  Haskell: The Craft of Functional Programming+--  Simon Thompson+--  (c) Addison-Wesley, 1996-2011.+--+--  PerformanceIS.hs+--+-----------------------------------------------------------------------++module Main where++-- main = putStrLn (show (sumI 1 1000000))+-- main = putStrLn (show (sumIA 1 1000000))+main = putStrLn (show (sumIS 1 1000000))++sumI :: Integer -> Integer -> Integer++sumI n m+ | n>m       = 0+ | otherwise = n + sumI (n+1) m++sumIA :: Integer -> Integer -> Integer++sumIA n m = accIA n m 0++accIA n m s+ | n>m       = s+ | otherwise = accIA (n+1) m (n+s)++sumIS :: Integer -> Integer -> Integer++sumIS n m = accIS n m 0++accIS n m s+ | n>m       = s+ | otherwise = accIS (n+1) m $! (n+s)
Craft3e.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.2 name: Craft3e-version: 0.2.0.4+version: 0.2.0.5 license: MIT license-file: LICENSE copyright: (c) Simon Thompson@@ -40,6 +40,7 @@     QuickCheck >= 2.1 && < 3,     old-locale == 1.0.*,     time >= 1.1 && < 2,+    random >= 1.1 && < 1.3,     mtl >= 1.1 && < 2.3,     HUnit >= 1.2.0 && < 1.7,     open-browser >= 0.1.0.0 && < 0.5@@ -55,8 +56,9 @@     Chapter14_2     Chapter17     Chapter18+    Chapter19     Chapter2-    Chapter20+    Chapter21     Chapter3     Chapter4     Chapter5@@ -112,14 +114,22 @@     QueueState     RandomGen     ServerState-    TopLevelServe  +    TopLevelServe+    Minesweeper+    Minesweeper2+    Minesweeper3+    Minesweeper4+    Minesweeper5+    MineRandom+    Palin -  hs-source-dirs: . ./Calculator ./Chapter15 ./Chapter16 ./Chapter19 ./Simulation  ./Chapter20+  hs-source-dirs: . ./Calculator ./Chapter15 ./Chapter16 ./Chapter20 ./Simulation  ./Chapter21 ./Minesweeper ./Palindromes  executable performanceI   main-is:     PerformanceI.hs-  hs-source-dirs: ./Chapter20+  hs-source-dirs: ./Chapter21   default-language: Haskell2010+  ghc-options: -rtsopts   build-depends:     base >= 4 && < 5,     Craft3e@@ -127,16 +137,18 @@  executable performanceIA   main-is:     PerformanceIA.hs-  hs-source-dirs: ./Chapter20+  hs-source-dirs: ./Chapter21   default-language: Haskell2010+  ghc-options: -rtsopts   build-depends:     base >= 4 && < 5,     Craft3e  executable performanceIS   main-is:     PerformanceIS.hs-  hs-source-dirs: ./Chapter20+  hs-source-dirs: ./Chapter21   default-language: Haskell2010+  ghc-options: -rtsopts   build-depends:     base >= 4 && < 5,     Craft3e
+ Minesweeper/MineRandom.hs view
@@ -0,0 +1,97 @@+----------------------------------------------------------
+--							--
+--	MineRandom.hs					--
+--							--
+--	Simon Thompson					--
+--							--
+--	2002-2011					--
+--							--
+----------------------------------------------------------
+
+-- Choosing a random starting configuration for 
+-- a minesweeper game.
+
+-- Making dynamic choices: get the seed on each invocation.
+-- Have to refactor choices etc. to take the seed as a parameter.
+
+module MineRandom ( randomGrid, randomGridDyn ) where
+import System.Random
+import System.IO.Unsafe ( unsafePerformIO )
+import Data.Time.Clock.POSIX ( getPOSIXTime )
+import Data.List ( insert , nub )
+
+-- Generate a random combination of m elements from n 
+-- i.e. choice of 0, 1, ..., n-1.
+-- The algorithm used makes repeated random choices until m different
+-- values are found.
+-- Perfectly efficient for n=100, m=40; not for 1000,400.
+-- Assumes that m<=n.
+-- Postcondition: the result is in ascending order; no duplicates.
+-- 16.6.02 seed is made a parameter
+
+choices :: Int -> Int -> Int -> [Int]
+
+choices seed n m
+  = fst (choicesAux ([],rands))
+    where
+    
+    choicesAux :: ([Int],[Int]) -> ([Int],[Int])
+    choicesAux (cs,(r:rs))
+      | length cs >= m 	= (cs,[])
+      | otherwise	= choicesAux (nub (insert r cs) , rs)
+      
+    rands :: [Int]
+    rands = randomRs (0::Int,n-1) (mkStdGen seed)
+    
+-- A random startup
+
+-- A seed for the random numbers is given by system time in seconds.
+-- A value is chosen once per session: the value persists through a
+-- session.
+
+sessionSeed :: Int
+
+sessionSeed = round (unsafePerformIO getPOSIXTime)
+
+-- A list of n choices from an m*p matrix
+-- 	m = row length
+--	p = column height
+-- Assumes that the postcondition for choices holds.
+-- 16.6.02 seed is made a parameter to the old randomGrid, now
+-- renamed randomGridMake.
+
+randomGridMake :: Int -> Int -> Int -> Int -> [[Bool]]
+
+randomGridMake seed n m p 
+  = pad
+    where
+    
+    makeMatrix :: Int -> [Int] -> [[Bool]]
+
+    makeMatrix i cs
+      | cs==[]		= []
+      | otherwise
+        = convert first : makeMatrix (i+1) rest
+	  where
+	  (first,rest) = span ((==i).(flip div m)) cs
+	  convert ns 
+	     = map check [0 .. m-1]
+	       where
+	       check n = elem n [ x `mod` m | x<-ns ]
+
+    rows = makeMatrix 0 (choices seed (m*p) n)
+     
+    pad = rows ++ replicate (p - length rows) (replicate m False)
+
+-- Random grid with a per-session seed.
+
+randomGrid :: Int -> Int -> Int -> [[Bool]]
+
+randomGrid = randomGridMake sessionSeed 
+
+-- Random grid with a per-invocation seed.
+
+randomGridDyn :: Int -> Int -> Int -> Int -> [[Bool]]
+
+randomGridDyn 
+  = randomGridMake 
+ Minesweeper/Minesweeper.hs view
@@ -0,0 +1,250 @@+----------------------------------------------------------
+--							--
+--	Minesweeper.hs					--
+--							--
+--	Simon Thompson					--
+--							--
+--      2002-2011                                       --
+--                                                      --
+----------------------------------------------------------
+
+{-# LANGUAGE FlexibleInstances #-}
+
+-- NB: Requires pragma above for instance declaration of
+-- non-atomic type: 
+--	instance AddThree [Int] where ...
+
+-- The board is represented by a list of lists. It is a
+-- global assumption that this is rectangular, that is all
+-- component lists have the same length.
+-- It is also assumed that grids are nonempty.
+
+module Minesweeper where
+import MineRandom ( randomGrid )
+import Data.List ( (\\) )
+
+
+type Config = [[Bool]]
+
+type Count  = [[Int]]
+
+class AddThree a where
+  add3 :: a -> a -> a -> a
+  zero :: a
+  addOffset :: [a] -> [a]
+  addOffset = zipOffset3 add3 zero
+  
+instance AddThree Int where
+  add3 n m p = n+m+p
+  zero       = 0
+
+instance AddThree [Int] where
+  add3 = zipWith3 add3
+  zero = repeat zero
+
+-- Combine elementwise (i.e. zipWith3) the three lists:
+--
+--	 z,a0,a1,a2,...
+--	a0,a1,a2,...,an
+--      a1,a2,...,an,z
+--
+-- using the ternary function f
+-- Example: f is addition of three numbers, z is zero.
+
+zipOffset3 :: (a -> a -> a -> a) -> a -> [a] -> [a]
+
+zipOffset3 f z xs = zipWith3 f (z:xs) xs (tail xs ++ [z])
+
+-- From the grid of occupation (Boolean) calculate the
+-- number of occupied adjacent squares.
+-- Note that the stone in the square itself is also
+-- counted.
+
+countConfig :: [[Bool]] -> [[Int]]
+
+countConfig = addOffset . map addOffset . makeNumeric
+
+-- A variant of countConfig which doesn't count the stone in
+-- the square itself.
+
+countConfigLess :: [[Bool]] -> [[Int]]
+
+countConfigLess bs 
+  = zipWith (zipWith (-)) (countConfig bs) (makeNumeric bs)
+
+-- Boolean matrix to numeric matrix; True to 1, 
+-- False to 0.
+
+makeNumeric :: [[Bool]] -> [[Int]]
+
+makeNumeric = map (map (\b -> if b then 1 else 0))
+
+-- A 3*3 Boolean test matrix.
+
+test1 = [[True, False, True],[True,True,True],[False,True,True]]
+
+-- Printing the grid
+
+showGrid :: [[Int]] -> String
+
+showGrid nss = "   " ++ take (length (head nss)) ['a' .. 'z'] ++ "\n" ++
+             concat (zipWith f [0 .. length nss - 1] nss)
+	     where
+	     f n ns = pad 3 (show n) ++ concat (map show ns) ++ "\n"
+
+pad :: Int -> String -> String
+
+pad n st
+  | len <= n		= st ++ replicate (n - len) ' ' 
+  | otherwise		= take n st
+    where
+    len = length st
+
+showTest1 :: IO ()
+
+showTest1 = putStr $ showGrid $ countConfig test1
+
+showGrid3 :: IO ()
+
+showGrid3 = putStr $ showGrid $ map (map (\b -> if b then 1 else 0)) test3
+
+
+showTest3 :: IO ()
+
+showTest3 = putStr $ showGrid $ countConfig test3
+
+tester3 :: IO ()
+
+tester3 = showGrid3 >> showTest3
+
+
+test3 = randomGrid 20 10 10
+
+
+-- Strength of the product functor on the left
+
+appLeft :: (a -> b) -> (a,c) -> (b,c)
+
+appLeft f (x,y) = (f x , y)
+
+-- Update list xs at index n to have value f (xs!!n)
+-- Handles out of range indices
+	     
+update :: Int -> (a -> a) -> [a] -> [a]
+
+update n f xs = front ++ rear
+		where
+		(front,rest) = splitAt n xs
+		rear = case rest of
+			[]	-> []
+			(h:t)	-> f h:t
+			
+-- Update an array to have value x at position (n,m)			
+ 
+updateArray :: Int -> Int -> a -> [[a]] -> [[a]]
+
+updateArray n m x xss = update n (update m (const x)) xss
+
+-- Show play
+-- Assumes that the two arrays are of the same shape
+-- The second array gives the adjacency count of the cell,
+-- whilst the first indicates whether or not it is uncovered.
+
+
+showPlay :: [[Bool]] -> [[Int]] -> String
+
+showPlay ess nss = "   " ++ take (length (head nss)) ['a' .. 'z'] ++ "\n" ++
+             concat (zipWith3 f [0 .. length nss - 1] ess nss)
+	     where
+	     f n es ns = pad 3 (show n) ++ concat (zipWith showCell es ns) ++ "\n"
+
+-- How to show the value in a particular cell.
+
+showCell :: Bool -> Int -> String
+
+showCell b n = if not b then "X"
+                        else if n==0 then " "
+			             else show n
+
+
+showTest2 :: IO ()
+
+showTest2 = putStr $ showPlay showing (countConfig test1)
+
+showing = [[True, False, False],[True, False, True],[True,True,True]]
+
+
+
+
+playGame :: IO ()
+
+playGame = 
+   playGameGrid showing
+
+   where
+
+   grid      = randomGrid 20 10 10
+   count     = countConfig grid			
+   countLess = countConfigLess grid	-- Added 26.4.02 (superfluous)
+   showing   = map (map (const False)) grid
+
+   playGameGrid :: [[Bool]] -> IO ()
+
+   playGameGrid showing =
+     do { putStr (showPlay showing count) ;
+          rowCh <- getChar ;
+	  let { row = fromEnum rowCh - fromEnum '0' } ;
+	  colCh <- getChar ;
+	  let { col = fromEnum colCh - fromEnum 'a' } ;
+	  putStr "\n" ;
+	  if grid!!row!!col then do { putStr "LOST!" ; return () }
+	  else
+	    playGameGrid (uncoverNbhrs count [(row,col)] (row,col) showing)
+	}
+     
+-- Transitively uncover all the neighbours of all the points in a list.
+-- Repeatedly applies uncoverNbhrs
+
+uncoverNbhrsList :: [[Int]] -> [(Int,Int)] -> [(Int,Int)] -> 
+                    [[Bool]] -> [[Bool]]
+
+uncoverNbhrsList count avoid
+  = foldr (.) id . map (uncoverNbhrs count avoid)
+
+-- Transitively uncover all the neighbours of a point.
+-- First uncover the immediate neighbours, then call recursively on
+-- all the neighbours with zero adjacency count.
+   
+uncoverNbhrs :: [[Int]] -> [(Int,Int)] -> (Int,Int) -> 
+                [[Bool]] -> [[Bool]]
+
+uncoverNbhrs count avoid (p,q)
+  = uncoverNbhrsList count (avoid++nbhrs count (p,q)) 
+                           (nullNbhrs count (p,q) \\ avoid) 
+    .
+    ( foldr (.) id $ 
+      map ((flip.uncurry) updateArray True) (nbhrs count (p,q)) )
+
+-- What are the neighbours of a point?
+
+nbhrs :: [[Int]] -> (Int,Int) -> [(Int,Int)]
+
+nbhrs count (p,q)
+  = filter inGrid [ (p-1,q-1), (p-1,q), (p-1,q+1),
+                    (p,q-1),   (p,q),   (p,q+1),
+		    (p+1,q-1), (p+1,q), (p+1,q+1) ]
+    where
+    inGrid (s,t) = 0<=s && s <= rows &&
+                   0<=t && t <= cols
+    rows = length count - 1
+    cols = length (head count) -1
+
+-- What are the null nbhrs?
+
+nullNbhrs :: [[Int]] -> (Int,Int) -> [(Int,Int)]
+
+nullNbhrs count (p,q)
+  = filter zeroVal (nbhrs count (p,q))
+    where
+    zeroVal (s,t) = count!!s!!t==0
+    
+ Minesweeper/Minesweeper2.hs view
@@ -0,0 +1,407 @@+----------------------------------------------------------
+--							--
+--	Minesweeper2.hs					--
+--							--
+--	Simon Thompson					--
+--							--
+--      2002-2011                                       --
+--                                                      --
+----------------------------------------------------------
+
+{-# LANGUAGE FlexibleInstances #-}
+
+
+-- NB: Requires pragma above for instance declaration of
+-- non-atomic type: 
+--	instance AddThree [Int] where ...
+
+-- Modifies Minesweeper.hs, by adding choice of reveal and mark
+
+-- The board is represented by a list of lists. It is a
+-- global assumption that this is rectangular, that is all
+-- component lists have the same length.
+-- It is also assumed that grids are nonempty.
+
+module Minesweeper2 where
+import MineRandom ( randomGrid )
+import Data.List ( (\\), zipWith4, nub )
+
+
+type Config = [[Bool]]
+
+type Count  = [[Int]]
+
+class AddThree a where
+  add3 :: a -> a -> a -> a
+  zero :: a
+  addOffset :: [a] -> [a]
+  addOffset = zipOffset3 add3 zero
+  
+instance AddThree Int where
+  add3 n m p = n+m+p
+  zero       = 0
+
+instance AddThree [Int] where
+  add3 = zipWith3 add3
+  zero = repeat zero
+
+-- Combine elementwise (i.e. zipWith3) the three lists:
+--
+--	 z,a0,a1,a2,...
+--	a0,a1,a2,...,an
+--      a1,a2,...,an,z
+--
+-- using the ternary function f
+-- Example: f is addition of three numbers, z is zero.
+
+zipOffset3 :: (a -> a -> a -> a) -> a -> [a] -> [a]
+
+zipOffset3 f z xs = zipWith3 f (z:xs) xs (tail xs ++ [z])
+
+-- From the grid of occupation (Boolean) calculate the
+-- number of occupied adjacent squares.
+-- Note that the stone in the square itself is also
+-- counted.
+
+countConfig :: [[Bool]] -> [[Int]]
+
+countConfig = addOffset . map addOffset . makeNumeric
+
+-- A variant of countConfig which doesn't count the stone in
+-- the square itself.
+
+countConfigLess :: [[Bool]] -> [[Int]]
+
+countConfigLess bs 
+  = zipWith (zipWith (-)) (countConfig bs) (makeNumeric bs)
+
+-- Boolean matrix to numeric matrix; True to 1, 
+-- False to 0.
+
+makeNumeric :: [[Bool]] -> [[Int]]
+
+makeNumeric = map (map (\b -> if b then 1 else 0))
+
+-- A 3*3 Boolean test matrix.
+
+test1 = [[True, False, True],[True,True,True],[False,True,True]]
+
+-- Printing the grid
+
+showGrid :: [[Int]] -> String
+
+showGrid nss = "   " ++ take (length (head nss)) ['a' .. 'z'] ++ "\n" ++
+             concat (zipWith f [0 .. length nss - 1] nss)
+	     where
+	     f n ns = pad 3 (show n) ++ concat (map show ns) ++ "\n"
+
+pad :: Int -> String -> String
+
+pad n st
+  | len <= n		= st ++ replicate (n - len) ' ' 
+  | otherwise		= take n st
+    where
+    len = length st
+
+-- Strength of the product functor on the left
+
+appLeft :: (a -> b) -> (a,c) -> (b,c)
+
+appLeft f (x,y) = (f x , y)
+
+-- Update list xs at index n to have value f (xs!!n)
+-- Handles out of range indices
+	     
+update :: Int -> (a -> a) -> [a] -> [a]
+
+update n f xs = front ++ rear
+		where
+		(front,rest) = splitAt n xs
+		rear = case rest of
+			[]	-> []
+			(h:t)	-> f h:t
+			
+-- Update an array to have value x at position (n,m)			
+ 
+updateArray :: Int -> Int -> a -> [[a]] -> [[a]]
+
+updateArray n m x xss = update n (update m (const x)) xss
+
+-- Show play
+-- Assumes that the two arrays are of the same shape
+-- The second array gives the adjacency count of the cell,
+-- whilst the first indicates whether or not it is uncovered.
+
+
+showPlay :: [[Bool]] -> [[Bool]] -> [[Int]] -> String
+
+showPlay ess mss nss 
+           = "   " ++ take (length (head nss)) ['a' .. 'z'] ++ "\n" ++
+             concat (zipWith4 f [0 .. length nss - 1] ess mss nss)
+	     where
+	     f n es ms ns 
+	       = pad 3 (show n) ++ concat (zipWith3 showCell es ms ns) ++ "\n"
+
+-- How to show the value in a particular cell.
+
+showCell :: Bool -> Bool -> Int -> String
+
+showCell showing marked n 
+	= if marked then "X"
+	     else if not showing then "."
+                 else if n==0 then " "
+		     else show n
+
+
+-- Play the game; pass in the number of mines
+-- and the (square) board size as initial arguments.
+
+playGame :: Int -> Int -> IO ()
+
+playGame mines size = 
+   playGameGrid showing marked
+
+   where
+
+   grid      = randomGrid mines size size
+   count     = countConfig grid			
+   showing   = map (map (const False)) grid
+   marked    = map (map (const False)) grid
+   
+   playGameGrid :: [[Bool]] -> [[Bool]] -> IO ()
+
+   playGameGrid showing marked =
+     do { putStr (showPlay showing marked count) ;
+          choice <- getChar ;
+	  if choice=='q' 				-- quit
+	  then 
+	   do { putStr "\nquit" ; return () }
+	  else if not (elem choice "smur")		-- ignore illegal
+	  then						-- choice
+	   do { putStr "\n" ; playGameGrid showing marked }
+	  else 
+	   do {
+           rowCh <- getChar ;				-- get row
+	   let { row = fitRange size (fromEnum rowCh - fromEnum '0') } ; 
+	   colCh <- getChar ;				-- and column
+	   let { col = fitRange size (fromEnum colCh - fromEnum 'a') } ;
+	   putStr "\n" ;
+	   case choice of
+	    'm' -> playGameGrid showing (updateArray row col True marked)
+	    'u' -> playGameGrid showing (updateArray row col False marked)
+	    'r' -> if grid!!!(row,col) 
+	             then (do { putStr "LOST!" ; return () })
+	             else
+	                (playGameGrid (uncoverClosure count (row,col) showing)
+	                              marked)
+	    's' -> do { putStr $ showInfo count showing marked row col ; 
+	                putStr "---------\n" ;
+	                putStr $ showEquations $ fixSplit $
+			         getInfo count showing marked row col ;
+	                playGameGrid showing marked }
+	       }
+	}
+
+-- Finding the closure of a point / set of points.
+-- The worker functions: doClosure, doClosureList, carry around a 
+-- list of points already visited.
+
+closure :: [[Int]] -> (Int,Int) -> [(Int,Int)]
+
+closure count point = doClosure count point []
+
+-- doClosure, doClosureList use a variant of the algorithm 
+-- on pp333-4 of craft2e.
+
+doClosure :: [[Int]] -> (Int,Int) -> [(Int,Int)] -> [(Int,Int)]
+
+doClosure count point avoid
+  | count!!!point /= 0	= [point]
+  | otherwise	
+    = point : doClosureList count nbs (point:avoid)
+      where
+      nbs = nbhrs count point
+
+doClosureList :: [[Int]] -> [(Int,Int)] -> [(Int,Int)] -> [(Int,Int)]
+
+doClosureList count [] avoid = []
+
+doClosureList count (point: points) avoid
+  = next ++ doClosureList count points (avoid ++ next)
+    where
+    next = if elem point avoid
+           then [point]
+	   else doClosure count point avoid
+
+-- Uncover all the points in the closure
+
+uncoverClosure :: [[Int]] -> (Int,Int) -> [[Bool]] -> [[Bool]]
+
+uncoverClosure count point 
+  = foldr (.) id $ 
+    map ((flip.uncurry) updateArray True) (closure count point)
+
+-- What are the neighbours of a point?
+
+nbhrs :: [[Int]] -> (Int,Int) -> [(Int,Int)]
+
+nbhrs count (p,q)
+  = filter inGrid [ (p-1,q-1), (p-1,q), (p-1,q+1),
+                    (p,q-1),   (p,q),   (p,q+1),
+		    (p+1,q-1), (p+1,q), (p+1,q+1) ]
+    where
+    inGrid (s,t) = 0<=s && s <= rows &&
+                   0<=t && t <= cols
+    rows = length count - 1
+    cols = length (head count) -1
+
+-- Push an integer value into the range 
+--	0 .. r-1
+
+fitRange :: Int -> Int -> Int
+
+fitRange r val
+  | 0<=val && val<r	= val
+  | val<0		= 0
+  | val>=r 		= r-1
+
+-- Array lookup operation
+
+(!!!) :: [[a]] -> (Int,Int) -> a
+
+xss!!!(p,q) = xss!!p!!q
+
+-- Showing the information about a given cell,
+-- in the context of certain known information:
+--	count showing marked
+-- Produces an equation corresponding to each neighbour
+-- which has its value showing.
+-- Count zero for showing zeroes and 1 for marked cells
+-- i.e. assumes that markings are correct.
+
+-- Refactored as getInfoCell below ....
+
+getInfo :: [[Int]] -> [[Bool]] -> [[Bool]] -> Int -> Int -> Equations
+
+getInfo count showing marked row col
+  = map (uncurry (getInfoCell count showing marked))
+        [ point | point <- nbhrs count (row,col) , showing!!!point ]
+
+showInfo :: [[Int]] -> [[Bool]] -> [[Bool]] -> Int -> Int -> String
+
+showInfo count showing marked row col 
+  = showEquations (getInfo count showing marked row col)
+			  
+type Equations = [Equation]
+type Equation  = (Int, [(Int,Int)])
+
+-- Initial program for the information extracts it and immediately
+-- shows it. Subsequently refactored to produce a data structure
+-- containing the information, and a corresponding show function over
+-- the data structure.
+
+-- Call this separate producer and consumer ... allows whatever is
+-- produced to be used in more than one way.
+-- Can envisage the converse too: merging producer and consumer,
+-- particularly if there's only one use of the producer in the program.
+
+getInfoCell :: [[Int]] -> [[Bool]] -> [[Bool]] -> Int -> Int -> Equation 
+
+getInfoCell count showing marked s t 
+  = ( (count!!!(s,t) - marks) , 
+      [ point | point <- nbrs, not (showing!!!point), 
+    			       not (marked!!!point) ]
+    )
+    where 
+    nbrs              = nbhrs count (s,t)
+    marks             = sum [ 1 | point<-nbrs , marked!!!point ]
+
+-- Showing the information in a cell
+    
+showInfoCell :: [[Int]] -> [[Bool]] -> [[Bool]] -> Int -> Int -> String 
+
+showInfoCell count showing marked s t 
+  = showEquation (getInfoCell count showing marked s t)
+
+showEquations = concat . (map showEquation)
+
+showEquation :: Equation -> String
+
+showEquation (lhs, rhs) 
+  = show lhs ++ " = " ++ showPoints rhs ++ "\n"
+
+showRow :: Int -> String
+showRow           = show
+
+showCol :: Int -> String
+showCol t         = [ toEnum (t + fromEnum 'a') ]
+
+showPoint :: (Int,Int) -> String
+showPoint (p,q)   = showRow p ++ showCol q
+
+showPoints :: [(Int,Int)] -> String
+showPoints []     = "none"
+showPoints [p]    = showPoint p
+showPoints (p:ps) = showPoint p ++ " + " ++ showPoints ps
+
+-- Reducing a list of equations to a normal form
+
+-- Is one list a sublist of the other?
+-- It is assumed that the elements appear in the same order, 
+-- without repetitions.
+
+subList :: Eq a => [a] -> [a] -> Bool
+
+subList [] _     = True
+subList (_:_) [] = False
+subList (x:xs) (y:ys)
+  | x==y	= subList xs ys
+  | otherwise	= subList (x:xs) ys
+
+-- The difference of two lists;
+-- only applied when the first is a subList of the second.
+
+listDiff :: Eq a => [a] -> [a] -> [a]
+
+listDiff [] ys	= ys
+listDiff (_:_) [] = error "listDiff applied to non-subList"
+listDiff (x:xs) (y:ys) 
+  | x==y	= listDiff xs ys
+  | otherwise	= y : listDiff (x:xs) ys
+
+-- Only splits when the first rhs is a sublist of the second
+-- and a proper sublist at that.
+
+splitEq :: Equation -> Equation -> Equation
+
+splitEq e1@(l1,r1) e2@(l2,r2)
+  | e1==e2		= e2
+  | subList r1 r2	= (l2-l1 , listDiff r1 r2)
+  | otherwise		= e2
+
+
+-- Split a set (list) of equations
+
+splitEqs :: [Equation] -> [Equation]
+
+splitEqs eqs
+  = foldr (.) id (map map (map splitEq eqs)) eqs
+
+-- Generic fixpt operator
+
+fixpt :: Eq a => (a -> a) -> a -> a
+
+fixpt f x
+  = g x
+    where
+    g y
+  	| y==next	= y
+  	| otherwise	= g next
+    	  where
+	  next = f y
+
+fixSplit :: [Equation] -> [Equation]
+
+fixSplit = fixpt (nub.splitEqs)
+
+
+ Minesweeper/Minesweeper3.hs view
@@ -0,0 +1,498 @@+----------------------------------------------------------
+--							--
+--	Minesweeper3.hs					--
+--							--
+--	Simon Thompson					--
+--							--
+--      2002-2011                                       --
+--                                                      --
+----------------------------------------------------------
+
+{-# LANGUAGE FlexibleInstances #-}
+
+
+-- NB: Requires pragma above for instance declaration of
+-- non-atomic type: 
+--	instance AddThree [Int] where ...
+
+-- Modifies Minesweeper2.hs, by ... (to be completed)
+
+-- The board is represented by a list of lists. It is a
+-- global assumption that this is rectangular, that is all
+-- component lists have the same length.
+-- It is also assumed that counts are nonempty.
+
+module Minesweeper3 where
+import MineRandom ( randomGrid )
+import Data.List ( (\\), zipWith4, nub )
+
+
+type Config = [[Bool]]
+
+type Count  = [[Int]]
+
+class AddThree a where
+  add3 :: a -> a -> a -> a
+  zero :: a
+  addOffset :: [a] -> [a]
+  addOffset = zipOffset3 add3 zero
+  
+instance AddThree Int where
+  add3 n m p = n+m+p
+  zero       = 0
+
+instance AddThree [Int] where
+  add3 = zipWith3 add3
+  zero = repeat zero
+
+-- Combine elementwise (i.e. zipWith3) the three lists:
+--
+--	 z,a0,a1,a2,...
+--	a0,a1,a2,...,an
+--      a1,a2,...,an,z
+--
+-- using the ternary function f
+-- Example: f is addition of three numbers, z is zero.
+
+zipOffset3 :: (a -> a -> a -> a) -> a -> [a] -> [a]
+
+zipOffset3 f z xs = zipWith3 f (z:xs) xs (tail xs ++ [z])
+
+-- From the grid of occupation (Boolean) calculate the
+-- number of occupied adjacent squares.
+-- Note that the stone in the square itself is also
+-- counted.
+
+countConfig :: [[Bool]] -> [[Int]]
+
+countConfig = addOffset . map addOffset . makeNumeric
+
+-- A variant of countConfig which doesn't count the stone in
+-- the square itself.
+
+countConfigLess :: [[Bool]] -> [[Int]]
+
+countConfigLess bs 
+  = zipWith (zipWith (-)) (countConfig bs) (makeNumeric bs)
+
+-- Boolean matrix to numeric matrix; True to 1, 
+-- False to 0.
+
+makeNumeric :: [[Bool]] -> [[Int]]
+
+makeNumeric = map (map (\b -> if b then 1 else 0))
+
+-- A 3*3 Boolean test matrix.
+
+test1 = [[True, False, True],[True,True,True],[False,True,True]]
+
+-- Printing the grid
+
+showGrid :: [[Int]] -> String
+
+showGrid nss = "   " ++ take (length (head nss)) ['a' .. 'z'] ++ "\n" ++
+             concat (zipWith f [0 .. length nss - 1] nss)
+	     where
+	     f n ns = pad 3 (show n) ++ concat (map show ns) ++ "\n"
+
+pad :: Int -> String -> String
+
+pad n st
+  | len <= n		= st ++ replicate (n - len) ' ' 
+  | otherwise		= take n st
+    where
+    len = length st
+
+-- Strength of the product functor on the left
+
+appLeft :: (a -> b) -> (a,c) -> (b,c)
+
+appLeft f (x,y) = (f x , y)
+
+-- Update list xs at index n to have value f (xs!!n)
+-- Handles out of range indices
+	     
+update :: Int -> (a -> a) -> [a] -> [a]
+
+update n f xs = front ++ rear
+		where
+		(front,rest) = splitAt n xs
+		rear = case rest of
+			[]	-> []
+			(h:t)	-> f h:t
+			
+-- Update an array to have value x at position (n,m)			
+ 
+updateArray :: Int -> Int -> a -> [[a]] -> [[a]]
+
+updateArray n m x xss = update n (update m (const x)) xss
+
+-- Show play
+-- Assumes that the two arrays are of the same shape
+-- The second array gives the adjacency count of the cell,
+-- whilst the first indicates whether or not it is uncovered.
+
+
+showPlay :: [[Bool]] -> [[Bool]] -> [[Int]] -> String
+
+showPlay ess mss nss 
+           = "   " ++ take (length (head nss)) ['a' .. 'z'] ++ "\n" ++
+             concat (zipWith4 f [0 .. length nss - 1] ess mss nss)
+	     where
+	     f n es ms ns 
+	       = pad 3 (show n) ++ concat (zipWith3 showCell es ms ns) ++ "\n"
+
+-- How to show the value in a particular cell.
+
+showCell :: Bool -> Bool -> Int -> String
+
+showCell showing marked n 
+	= if marked then "X"
+	     else if not showing then "."
+                 else if n==0 then " "
+		     else show n
+
+
+-- Play the game; pass in the number of mines
+-- and the (square) board size as initial arguments.
+
+playGame :: Int -> Int -> IO ()
+
+playGame mines size = 
+   playGameGrid grid count showing marked
+
+   where
+
+   grid      = randomGrid mines size size
+   count     = countConfig grid			
+   showing   = map (map (const False)) grid
+   marked    = map (map (const False)) grid
+   
+playGameGrid :: [[Bool]] -> [[Int]] -> [[Bool]] -> [[Bool]] -> IO ()
+
+playGameGrid grid count showing marked =
+     do { putStr (showPlay showing marked count) ;
+          choice <- getChar ;
+	  if choice=='q' 				-- quit
+	  then 
+	   do { putStr "\nquit" ; return () }
+	  else if not (elem choice "smurat")		-- ignore illegal
+	  then						-- choice
+	   do { putStr "\n" ; playGameGrid grid count showing marked }
+	  else 
+	   do {
+           rowCh <- getChar ;				-- get row
+	   let { row = fitRange size (fromEnum rowCh - fromEnum '0') } ; 
+	   colCh <- getChar ;				-- and column
+	   let { col = fitRange size (fromEnum colCh - fromEnum 'a') } ;
+	   putStr "\n" ;
+	   case choice of
+	    'm' -> playGameGrid grid count showing (updateArray row col True marked)
+	    'u' -> playGameGrid grid count showing (updateArray row col False marked)
+	    'r' -> if grid!!!(row,col) 
+	             then (do { putStr "LOST!" ; return () })
+	             else
+	                (playGameGrid grid count 
+			              (uncoverClosure count (row,col) showing)
+	                              marked)
+	    's' -> do { putStr $ showInfo count showing marked row col ; 
+	                putStr "---------\n" ;
+	                putStr $ showEquations $ fixSplit $
+			         getInfo count showing marked row col ;
+	                playGameGrid grid count showing marked }
+	    'a' -> let {eqs = fixSplit (getInfo count showing marked row col);
+	                (newShow,newMark) = playAutoOne grid count
+						showing marked row col}
+		   in do {
+	                putStr $ showEquations eqs ;
+			playGameGrid grid count newShow newMark }
+	    't' -> playAuto grid count showing marked [(row,col)]
+	       }
+	}
+	where size = length grid
+	
+-- Play one step automatically
+
+playAutoOne :: [[Bool]] -> [[Int]] -> [[Bool]] -> [[Bool]] -> 
+               Int -> Int -> ([[Bool]],[[Bool]])
+
+playAutoOne grid count showing marked row col
+ = let eqs = fixSplit (getInfo count showing marked row col)
+   in (updateShowByEqs eqs count showing,
+       updateMarkByEqs eqs marked)
+
+-- Play the game automatically from the information at point (n,m)
+-- Halts when no further progress made, and calls playGame.
+
+playAuto :: [[Bool]] -> [[Int]] -> [[Bool]] -> [[Bool]] -> [(Int,Int)] -> IO ()
+
+playAuto grid count showing marked []
+  = playGameGrid grid count showing marked
+playAuto grid count showing marked ((row,col):rest)
+ = let eqs = fixSplit (getInfo count showing marked row col)
+       (newShow,newMark) = playAutoOne grid count showing marked row col
+       newPts = makeNeg eqs ++ makePos eqs
+   in if (showing,marked)==(newShow,newMark) 
+   then playAuto grid count showing marked rest
+   else 
+   do { putStr $ showEquations eqs ;
+        putStr (showPlay showing marked count) ;
+	playAuto grid count newShow newMark (nub(newPts++rest)) }
+
+
+-- Finding the closure of a point / set of points.
+-- The worker functions: doClosure, doClosureList, carry around a 
+-- list of points already visited.
+
+closure :: [[Int]] -> (Int,Int) -> [(Int,Int)]
+
+closure count point = doClosure count point []
+
+-- doClosure, doClosureList use a variant of the algorithm 
+-- on pp333-4 of craft2e.
+
+doClosure :: [[Int]] -> (Int,Int) -> [(Int,Int)] -> [(Int,Int)]
+
+doClosure count point avoid
+  | count!!!point /= 0	= [point]
+  | otherwise	
+    = point : doClosureList count nbs (point:avoid)
+      where
+      nbs = nbhrs count point
+
+doClosureList :: [[Int]] -> [(Int,Int)] -> [(Int,Int)] -> [(Int,Int)]
+
+doClosureList count [] avoid = []
+
+doClosureList count (point: points) avoid
+  = next ++ doClosureList count points (avoid ++ next)
+    where
+    next = if elem point avoid
+           then [point]
+	   else doClosure count point avoid
+
+-- Uncover all the points in the closure
+
+uncoverClosure :: [[Int]] -> (Int,Int) -> [[Bool]] -> [[Bool]]
+
+uncoverClosure count point 
+  = foldr (.) id $ 
+    map ((flip.uncurry) updateArray True) (closure count point)
+
+-- What are the neighbours of a point?
+
+nbhrs :: [[Int]] -> (Int,Int) -> [(Int,Int)]
+
+nbhrs count (p,q)
+  = filter inGrid [ (p-1,q-1), (p-1,q), (p-1,q+1),
+                    (p,q-1),   (p,q),   (p,q+1),
+		    (p+1,q-1), (p+1,q), (p+1,q+1) ]
+    where
+    inGrid (s,t) = 0<=s && s <= rows &&
+                   0<=t && t <= cols
+    rows = length count - 1
+    cols = length (head count) -1
+
+-- Push an integer value into the range 
+--	0 .. r-1
+
+fitRange :: Int -> Int -> Int
+
+fitRange r val
+  | 0<=val && val<r	= val
+  | val<0		= 0
+  | val>=r 		= r-1
+
+-- Array lookup operation
+
+(!!!) :: [[a]] -> (Int,Int) -> a
+
+xss!!!(p,q) = xss!!p!!q
+
+-- Showing the information about a given cell,
+-- in the context of certain known information:
+--	count showing marked
+-- Produces an equation corresponding to each neighbour
+-- which has its value showing.
+-- Count zero for showing zeroes and 1 for marked cells
+-- i.e. assumes that markings are correct.
+
+-- Refactored as getInfoCell below ....
+
+getInfo :: [[Int]] -> [[Bool]] -> [[Bool]] -> Int -> Int -> Equations
+
+getInfo count showing marked row col
+  = map (uncurry (getInfoCell count showing marked))
+        [ point | point <- nbhrs count (row,col) , showing!!!point ]
+
+showInfo :: [[Int]] -> [[Bool]] -> [[Bool]] -> Int -> Int -> String
+
+showInfo count showing marked row col 
+  = showEquations (getInfo count showing marked row col)
+			  
+type Equations = [Equation]
+type Equation  = (Int, [(Int,Int)])
+
+-- Initial program for the information extracts it and immediately
+-- shows it. Subsequently refactored to produce a data structure
+-- containing the information, and a corresponding show function over
+-- the data structure.
+
+-- Call this separate producer and consumer ... allows whatever is
+-- produced to be used in more than one way.
+-- Can envisage the converse too: merging producer and consumer,
+-- particularly if there's only one use of the producer in the program.
+
+getInfoCell :: [[Int]] -> [[Bool]] -> [[Bool]] -> Int -> Int -> Equation 
+
+getInfoCell count showing marked s t 
+  = ( (count!!!(s,t) - marks) , 
+      [ point | point <- nbrs, not (showing!!!point), 
+    			       not (marked!!!point) ]
+    )
+    where 
+    nbrs              = nbhrs count (s,t)
+    marks             = sum [ 1 | point<-nbrs , marked!!!point ]
+
+-- Showing the information in a cell
+    
+showInfoCell :: [[Int]] -> [[Bool]] -> [[Bool]] -> Int -> Int -> String 
+
+showInfoCell count showing marked s t 
+  = showEquation (getInfoCell count showing marked s t)
+
+showEquations = concat . (map showEquation)
+
+showEquation :: Equation -> String
+
+showEquation (lhs, rhs) 
+  = show lhs ++ " = " ++ showPoints rhs ++ "\n"
+
+showRow :: Int -> String
+showRow           = show
+
+showCol :: Int -> String
+showCol t         = [ toEnum (t + fromEnum 'a') ]
+
+showPoint :: (Int,Int) -> String
+showPoint (p,q)   = showRow p ++ showCol q
+
+showPoints :: [(Int,Int)] -> String
+showPoints []     = "none"
+showPoints [p]    = showPoint p
+showPoints (p:ps) = showPoint p ++ " + " ++ showPoints ps
+
+-- Reducing a list of equations to a normal form
+
+-- Is one list a sublist of the other?
+-- It is assumed that the elements appear in the same order, 
+-- without repetitions.
+
+subList :: Eq a => [a] -> [a] -> Bool
+
+subList [] _     = True
+subList (_:_) [] = False
+subList (x:xs) (y:ys)
+  | x==y	= subList xs ys
+  | otherwise	= subList (x:xs) ys
+
+-- The difference of two lists;
+-- only applied when the first is a subList of the second.
+
+listDiff :: Eq a => [a] -> [a] -> [a]
+
+listDiff [] ys	= ys
+listDiff (_:_) [] = error "listDiff applied to non-subList"
+listDiff (x:xs) (y:ys) 
+  | x==y	= listDiff xs ys
+  | otherwise	= y : listDiff (x:xs) ys
+
+-- Only splits when the first rhs is a sublist of the second
+-- and a proper sublist at that.
+
+splitEq :: Equation -> Equation -> Equation
+
+splitEq e1@(l1,r1) e2@(l2,r2)
+  | e1==e2		= e2
+  | subList r1 r2	= (l2-l1 , listDiff r1 r2)
+  | otherwise		= e2
+
+
+-- Split a set (list) of equations
+
+splitEqs :: [Equation] -> [Equation]
+
+splitEqs eqs
+  = foldr (.) id (map map (map splitEq eqs)) eqs
+
+-- Generic fixpt operator
+
+fixpt :: Eq a => (a -> a) -> a -> a
+
+fixpt f x
+  = g x
+    where
+    g y
+  	| y==next	= y
+  	| otherwise	= g next
+    	  where
+	  next = f y
+
+fixSplit :: [Equation] -> [Equation]
+
+fixSplit = fixpt (nub.splitEqs)
+
+-- Added in Minesweeper3 ...
+
+-- Is an equation determinate?
+-- Could be determinate in setting all values to
+-- zero (deterNeg) or to one (deterPos)
+
+determined :: Equation -> Bool
+
+determined eq
+  = deterPos eq || deterNeg eq
+  
+deterPos,deterNeg :: Equation -> Bool
+
+deterPos (n,pts)
+  = n>0 && n==length pts
+
+deterNeg (n,pts) 
+  = n==0 && length pts > 0
+
+-- Find all the points to be made negative or positive
+-- from a set of Equations.
+
+makePos,makeNeg :: [Equation] -> [(Int,Int)]
+
+makeNeg = nub . concat . map snd . filter deterNeg
+makePos = nub . concat . map snd . filter deterPos
+
+-- Update a marking array according to the information 
+-- in a set of equations.
+
+updateMarkByEqs :: [Equation] -> [[Bool]] -> [[Bool]]
+
+updateMarkByEqs eqs marked
+  = updatePos marked
+    where
+    updatePos = foldr (.) id $ map updateP (makePos eqs)
+    updateP (n,m) = updateArray n m True 
+
+-- Update a showing array according to the info
+-- in a set of equations. In thie first version it
+-- failed to uncover the closure of the uncovered points.
+-- To do this, it has to be passed the grid count as well
+-- as the show matrix.
+
+updateShowByEqs :: [Equation] -> [[Int]] -> [[Bool]] -> [[Bool]]
+
+updateShowByEqs eqs count showing
+  = updateNeg showing
+    where
+    updateNeg = foldr (.) id $ map updateN (makeNeg eqs)
+    updateN (n,m) = uncoverClosure count (n,m)
+
+
+    
+ Minesweeper/Minesweeper4.hs view
@@ -0,0 +1,542 @@+----------------------------------------------------------
+--							--
+--	Minesweeper4.hs					--
+--							--
+--	Simon Thompson					--
+--							--
+--      2002-2011                                       --
+--                                                      --
+----------------------------------------------------------
+
+{-# LANGUAGE FlexibleInstances #-}
+
+
+-- NB: Requires pragma above for instance declaration of
+-- non-atomic type: 
+--	instance AddThree [Int] where ...
+
+-- Modifies Minesweeper3.hs, by refactoring two Ints to
+-- Int pairs. Notes below. Help option added.
+
+-- The board is represented by a list of lists. It is a
+-- global assumption that this is rectangular, that is all
+-- component lists have the same length.
+-- It is also assumed that counts are nonempty.
+
+-- REFACTOR
+-- Introduce a type of Points which are pairs of Int.
+--
+-- Modify functions which take curried points e.g.
+--	X -> Y -> Int -> Int -> ...
+-- to be uncurried
+--	X -> Y -> (Int,Int) -> ...
+--
+-- In most cases elements of type Point don't have to be
+-- a pair pattern any more, so (s,t) becomes point, say.
+--
+-- In the main loop adding a let definition of
+--   point = (row,col)
+-- changes the calls to the main functions.
+--
+-- Note also the interesting case in which there were 
+-- explict uses of uncurry, e.g.
+--  (flip.uncurry) updateArray
+-- which had to be recognised and dealt with.
+--
+-- Also need to deal with other type definitions containing (Int,Int)
+-- as a subtype.
+
+
+module Minesweeper4 where
+import MineRandom ( randomGrid )
+import Data.List ( (\\), zipWith4, nub )
+
+
+type Config = [[Bool]]
+
+type Count  = [[Int]]
+
+type Point = (Int,Int)		-- added in Minesweeper4
+
+class AddThree a where
+  add3 :: a -> a -> a -> a
+  zero :: a
+  addOffset :: [a] -> [a]
+  addOffset = zipOffset3 add3 zero
+  
+instance AddThree Int where
+  add3 n m p = n+m+p
+  zero       = 0
+
+instance AddThree [Int] where
+  add3 = zipWith3 add3
+  zero = repeat zero
+
+-- Combine elementwise (i.e. zipWith3) the three lists:
+--
+--	 z,a0,a1,a2,...
+--	a0,a1,a2,...,an
+--      a1,a2,...,an,z
+--
+-- using the ternary function f
+-- Example: f is addition of three numbers, z is zero.
+
+zipOffset3 :: (a -> a -> a -> a) -> a -> [a] -> [a]
+
+zipOffset3 f z xs = zipWith3 f (z:xs) xs (tail xs ++ [z])
+
+-- From the grid of occupation (Boolean) calculate the
+-- number of occupied adjacent squares.
+-- Note that the stone in the square itself is also
+-- counted.
+
+countConfig :: [[Bool]] -> [[Int]]
+
+countConfig = addOffset . map addOffset . makeNumeric
+
+-- A variant of countConfig which doesn't count the stone in
+-- the square itself.
+
+countConfigLess :: [[Bool]] -> [[Int]]
+
+countConfigLess bs 
+  = zipWith (zipWith (-)) (countConfig bs) (makeNumeric bs)
+
+-- Boolean matrix to numeric matrix; True to 1, 
+-- False to 0.
+
+makeNumeric :: [[Bool]] -> [[Int]]
+
+makeNumeric = map (map (\b -> if b then 1 else 0))
+
+-- A 3*3 Boolean test matrix.
+
+test1 = [[True, False, True],[True,True,True],[False,True,True]]
+
+-- Printing the grid
+
+showGrid :: [[Int]] -> String
+
+showGrid nss = "   " ++ take (length (head nss)) ['a' .. 'z'] ++ "\n" ++
+             concat (zipWith f [0 .. length nss - 1] nss)
+	     where
+	     f n ns = pad 3 (show n) ++ concat (map show ns) ++ "\n"
+
+pad :: Int -> String -> String
+
+pad n st
+  | len <= n		= st ++ replicate (n - len) ' ' 
+  | otherwise		= take n st
+    where
+    len = length st
+
+-- Strength of the product functor on the left
+
+appLeft :: (a -> b) -> (a,c) -> (b,c)
+
+appLeft f (x,y) = (f x , y)
+
+-- Update list xs at index n to have value f (xs!!n)
+-- Handles out of range indices
+	     
+update :: Int -> (a -> a) -> [a] -> [a]
+
+update n f xs = front ++ rear
+		where
+		(front,rest) = splitAt n xs
+		rear = case rest of
+			[]	-> []
+			(h:t)	-> f h:t
+			
+-- Update an array to have value x at position (n,m)			
+ 
+updateArray :: Point -> a -> [[a]] -> [[a]]
+
+updateArray (n,m) x xss = update n (update m (const x)) xss
+
+-- Show play
+-- Assumes that the two arrays are of the same shape
+-- The second array gives the adjacency count of the cell,
+-- whilst the first indicates whether or not it is uncovered.
+
+
+showPlay :: [[Bool]] -> [[Bool]] -> [[Int]] -> String
+
+showPlay ess mss nss 
+           = "   " ++ take (length (head nss)) ['a' .. 'z'] ++ "\n" ++
+             concat (zipWith4 f [0 .. length nss - 1] ess mss nss)
+	     where
+	     f n es ms ns 
+	       = pad 3 (show n) ++ concat (zipWith3 showCell es ms ns) ++ "\n"
+
+-- How to show the value in a particular cell.
+
+showCell :: Bool -> Bool -> Int -> String
+
+showCell showing marked n 
+	= if marked then "X"
+	     else if not showing then "."
+                 else if n==0 then " "
+		     else show n
+
+
+-- Play the game; pass in the number of mines
+-- and the (square) board size as initial arguments.
+
+playGame :: Int -> Int -> IO ()
+
+playGame mines size = 
+   playGameGrid grid count showing marked
+
+   where
+
+   grid      = randomGrid mines size size
+   count     = countConfig grid			
+   showing   = map (map (const False)) grid
+   marked    = map (map (const False)) grid
+   
+playGameGrid :: [[Bool]] -> [[Int]] -> [[Bool]] -> [[Bool]] -> IO ()
+
+playGameGrid grid count showing marked =
+     do { putStr (showPlay showing marked count) ;
+          choice <- getChar ;
+	  if choice=='q' 				-- quit
+	  then 
+	   do { putStr "\nquit" ; return () }
+	  else if choice=='h'
+	  then
+	   do { putStr helpInfo ; playGameGrid grid count showing marked }
+	  else if not (elem choice "smurat")		-- ignore illegal
+	  then						-- choice
+	   do { putStr "\n" ; playGameGrid grid count showing marked }
+	  else 
+	   do {
+           rowCh <- getChar ;				-- get row
+	   let { row = fitRange size (fromEnum rowCh - fromEnum '0') } ; 
+	   colCh <- getChar ;				-- and column
+	   let { col = fitRange size (fromEnum colCh - fromEnum 'a') } ;
+	   let { point = (row,col) } ;
+	   putStr "\n" ;
+	   case choice of
+	    'm' -> playGameGrid grid count showing (updateArray point True marked)
+	    'u' -> playGameGrid grid count showing (updateArray point False marked)
+	    'r' -> if grid!!!point 
+	             then (do { putStr "LOST!" ; return () })
+	             else
+	                (playGameGrid grid count 
+			              (uncoverClosure count point showing)
+	                              marked)
+	    's' -> do { putStr $ showInfo count showing marked point ; 
+	                putStr "---------\n" ;
+	                putStr $ showEquations $ fixSplit $
+			         getInfo count showing marked point ;
+	                playGameGrid grid count showing marked }
+	    'a' -> let {eqs = fixSplit (getInfo count showing marked point);
+	                (newShow,newMark) = playAutoOne grid count
+						showing marked point}
+		   in do {
+	                putStr $ showEquations eqs ;
+			playGameGrid grid count newShow newMark }
+	    't' -> playAuto grid count showing marked [point]
+	       }
+	}
+	where size = length grid
+
+helpInfo :: String
+
+helpInfo
+  = "\n\n q\tQuit\n\
+    \ h\tHelp information\n\
+    \ m7b\tMark position 7b\n\
+    \ u7b\tUnmark position 7b\n\
+    \ r7b\tReveal position 7b\n\
+    \ s7b\tShow equations at 7b\n\
+    \ a7b\tAutomatic turn at 7b\n\
+    \ t7b\tTransitive automatic from 7b\n\n"
+	
+-- Play one step automatically
+
+playAutoOne :: [[Bool]] -> [[Int]] -> [[Bool]] -> [[Bool]] -> 
+               Point -> ([[Bool]],[[Bool]])
+
+playAutoOne grid count showing marked point
+ = let eqs = fixSplit (getInfo count showing marked point)
+   in (updateShowByEqs eqs count showing,
+       updateMarkByEqs eqs marked)
+
+-- Play the game automatically from the information at point (n,m)
+-- Halts when no further progress made, and calls playGame.
+
+playAuto :: [[Bool]] -> [[Int]] -> [[Bool]] -> [[Bool]] -> [Point] -> IO ()
+
+playAuto grid count showing marked []
+  = playGameGrid grid count showing marked
+playAuto grid count showing marked (point:rest)
+ = let eqs = fixSplit (getInfo count showing marked point)
+       (newShow,newMark) = playAutoOne grid count showing marked point
+       newPts = makeNeg eqs ++ makePos eqs
+   in if (showing,marked)==(newShow,newMark) 
+   then playAuto grid count showing marked rest
+   else 
+   do { putStr $ showEquations eqs ;
+        putStr (showPlay showing marked count) ;
+	playAuto grid count newShow newMark (nub(newPts++rest)) }
+
+
+-- Finding the closure of a point / set of points.
+-- The worker functions: doClosure, doClosureList, carry around a 
+-- list of points already visited.
+
+closure :: [[Int]] -> Point -> [Point]
+
+closure count point = doClosure count point []
+
+-- doClosure, doClosureList use a variant of the algorithm 
+-- on pp333-4 of craft2e.
+
+doClosure :: [[Int]] -> Point -> [Point] -> [Point]
+
+doClosure count point avoid
+  | count!!!point /= 0	= [point]
+  | otherwise	
+    = point : doClosureList count nbs (point:avoid)
+      where
+      nbs = nbhrs count point
+
+doClosureList :: [[Int]] -> [Point] -> [Point] -> [Point]
+
+doClosureList count [] avoid = []
+
+doClosureList count (point: points) avoid
+  = next ++ doClosureList count points (avoid ++ next)
+    where
+    next = if elem point avoid
+           then [point]
+	   else doClosure count point avoid
+
+-- Uncover all the points in the closure
+
+uncoverClosure :: [[Int]] -> Point -> [[Bool]] -> [[Bool]]
+
+uncoverClosure count point 
+  = foldr (.) id $ 
+    map (flip updateArray True) (closure count point)
+
+-- What are the neighbours of a point?
+
+nbhrs :: [[Int]] -> Point -> [Point]
+
+nbhrs count (p,q)
+  = filter inGrid [ (p-1,q-1), (p-1,q), (p-1,q+1),
+                    (p,q-1),   (p,q),   (p,q+1),
+		    (p+1,q-1), (p+1,q), (p+1,q+1) ]
+    where
+    inGrid (s,t) = 0<=s && s <= rows &&
+                   0<=t && t <= cols
+    rows = length count - 1
+    cols = length (head count) -1
+
+-- Push an integer value into the range 
+--	0 .. r-1
+
+fitRange :: Int -> Int -> Int
+
+fitRange r val
+  | 0<=val && val<r	= val
+  | val<0		= 0
+  | val>=r 		= r-1
+
+-- Array lookup operation
+
+(!!!) :: [[a]] -> Point -> a
+
+xss!!!(p,q) = xss!!p!!q
+
+-- Showing the information about a given cell,
+-- in the context of certain known information:
+--	count showing marked
+-- Produces an equation corresponding to each neighbour
+-- which has its value showing.
+-- Count zero for showing zeroes and 1 for marked cells
+-- i.e. assumes that markings are correct.
+
+-- Refactored as getInfoCell below ....
+
+getInfo :: [[Int]] -> [[Bool]] -> [[Bool]] -> Point -> Equations
+
+getInfo count showing marked point
+  = map (getInfoCell count showing marked)
+        [ nb | nb <- nbhrs count point , showing!!!nb ]
+
+showInfo :: [[Int]] -> [[Bool]] -> [[Bool]] -> Point -> String
+
+showInfo count showing marked point 
+  = showEquations (getInfo count showing marked point)
+			  
+type Equations = [Equation]
+type Equation  = (Int, [Point])
+
+-- Initial program for the information extracts it and immediately
+-- shows it. Subsequently refactored to produce a data structure
+-- containing the information, and a corresponding show function over
+-- the data structure.
+
+-- Call this separate producer and consumer ... allows whatever is
+-- produced to be used in more than one way.
+-- Can envisage the converse too: merging producer and consumer,
+-- particularly if there's only one use of the producer in the program.
+
+getInfoCell :: [[Int]] -> [[Bool]] -> [[Bool]] -> Point -> Equation 
+
+getInfoCell count showing marked point
+  = ( (count!!!point - marks) , 
+      [ nb | nb <- nbrs, not (showing!!!nb), not (marked!!!nb) ]
+    )
+    where 
+    nbrs              = nbhrs count point
+    marks             = sum [ 1 | nb<-nbrs , marked!!!nb ]
+
+-- Showing the information in a cell
+    
+showInfoCell :: [[Int]] -> [[Bool]] -> [[Bool]] -> Point -> String 
+
+showInfoCell count showing marked point
+  = showEquation (getInfoCell count showing marked point)
+
+showEquations :: Equations -> String
+
+showEquations = concat . (map showEquation)
+
+showEquation :: Equation -> String
+
+showEquation (lhs, rhs) 
+  = show lhs ++ " = " ++ showPoints rhs ++ "\n"
+
+showRow :: Int -> String
+showRow           = show
+
+showCol :: Int -> String
+showCol t         = [ toEnum (t + fromEnum 'a') ]
+
+showPoint :: Point -> String
+showPoint (p,q)   = showRow p ++ showCol q
+
+showPoints :: [Point] -> String
+showPoints []     = "none"
+showPoints [p]    = showPoint p
+showPoints (p:ps) = showPoint p ++ " + " ++ showPoints ps
+
+-- Reducing a list of equations to a normal form
+
+-- Is one list a sublist of the other?
+-- It is assumed that the elements appear in the same order, 
+-- without repetitions.
+
+subList :: Eq a => [a] -> [a] -> Bool
+
+subList [] _     = True
+subList (_:_) [] = False
+subList (x:xs) (y:ys)
+  | x==y	= subList xs ys
+  | otherwise	= subList (x:xs) ys
+
+-- The difference of two lists;
+-- only applied when the first is a subList of the second.
+
+listDiff :: Eq a => [a] -> [a] -> [a]
+
+listDiff [] ys	= ys
+listDiff (_:_) [] = error "listDiff applied to non-subList"
+listDiff (x:xs) (y:ys) 
+  | x==y	= listDiff xs ys
+  | otherwise	= y : listDiff (x:xs) ys
+
+-- Only splits when the first rhs is a sublist of the second
+-- and a proper sublist at that.
+
+splitEq :: Equation -> Equation -> Equation
+
+splitEq e1@(l1,r1) e2@(l2,r2)
+  | e1==e2		= e2
+  | subList r1 r2	= (l2-l1 , listDiff r1 r2)
+  | otherwise		= e2
+
+
+-- Split a set (list) of equations
+
+splitEqs :: [Equation] -> [Equation]
+
+splitEqs eqs
+  = foldr (.) id (map map (map splitEq eqs)) eqs
+
+-- Generic fixpt operator
+
+fixpt :: Eq a => (a -> a) -> a -> a
+
+fixpt f x
+  = g x
+    where
+    g y
+  	| y==next	= y
+  	| otherwise	= g next
+    	  where
+	  next = f y
+
+fixSplit :: [Equation] -> [Equation]
+
+fixSplit = fixpt (nub.splitEqs)
+
+-- Added in Minesweeper3 ...
+
+-- Is an equation determinate?
+-- Could be determinate in setting all values to
+-- zero (deterNeg) or to one (deterPos)
+
+determined :: Equation -> Bool
+
+determined eq
+  = deterPos eq || deterNeg eq
+  
+deterPos,deterNeg :: Equation -> Bool
+
+deterPos (n,pts)
+  = n>0 && n==length pts
+
+deterNeg (n,pts) 
+  = n==0 && length pts > 0
+
+-- Find all the points to be made negative or positive
+-- from a set of Equations.
+
+makePos,makeNeg :: [Equation] -> [Point]
+
+makeNeg = nub . concat . map snd . filter deterNeg
+makePos = nub . concat . map snd . filter deterPos
+
+-- Update a marking array according to the information 
+-- in a set of equations.
+
+updateMarkByEqs :: [Equation] -> [[Bool]] -> [[Bool]]
+
+updateMarkByEqs eqs marked
+  = updatePos marked
+    where
+    updatePos = foldr (.) id $ map updateP (makePos eqs)
+    updateP pt = updateArray pt True 
+
+-- Update a showing array according to the info
+-- in a set of equations. In thie first version it
+-- failed to uncover the closure of the uncovered points.
+-- To do this, it has to be passed the grid count as well
+-- as the show matrix.
+
+updateShowByEqs :: [Equation] -> [[Int]] -> [[Bool]] -> [[Bool]]
+
+updateShowByEqs eqs count showing
+  = updateNeg showing
+    where
+    updateNeg = foldr (.) id $ map updateN (makeNeg eqs)
+    updateN   = uncoverClosure count
+
+
+    
+ Minesweeper/Minesweeper5.hs view
@@ -0,0 +1,563 @@+----------------------------------------------------------
+--							--
+--	Minesweeper5.hs					--
+--							--
+--	Simon Thompson					--
+--							--
+--      2002-2011                                       --
+--                                                      --
+----------------------------------------------------------
+
+{-# LANGUAGE FlexibleInstances #-}
+
+
+-- NB: Requires pragma above for instance declaration of
+-- non-atomic type: 
+--	instance AddThree [Int] where ...
+
+-- Modifies Minesweeper3.hs, by refactoring two Ints to
+-- Int pairs. Notes below. Help option added.
+
+-- The board is represented by a list of lists. It is a
+-- global assumption that this is rectangular, that is all
+-- component lists have the same length.
+-- It is also assumed that counts are nonempty.
+
+-- REFACTOR 3->4
+-- Introduce a type of Points which are pairs of Int.
+--
+-- Modify functions which take curried points e.g.
+--	X -> Y -> Int -> Int -> ...
+-- to be uncurried
+--	X -> Y -> (Int,Int) -> ...
+--
+-- In most cases elements of type Point don't have to be
+-- a pair pattern any more, so (s,t) becomes point, say.
+--
+-- In the main loop adding a let definition of
+--   point = (row,col)
+-- changes the calls to the main functions.
+--
+-- Note also the interesting case in which there were 
+-- explict uses of uncurry, e.g.
+--  (flip.uncurry) updateArray
+-- which had to be recognised and dealt with.
+--
+-- Also need to deal with other type definitions containing (Int,Int)
+-- as a subtype.
+
+
+-- REFACTOR 4->5
+--
+-- A uniform procedure for getting input (getInput)
+-- and for handling it......
+
+
+module Minesweeper5 where
+import MineRandom ( randomGrid )
+import Data.List ( (\\), zipWith4, nub )
+
+
+type Config = [[Bool]]
+
+type Count  = [[Int]]
+
+type Point = (Int,Int)		-- added in Minesweeper4
+
+class AddThree a where
+  add3 :: a -> a -> a -> a
+  zero :: a
+  addOffset :: [a] -> [a]
+  addOffset = zipOffset3 add3 zero
+  
+instance AddThree Int where
+  add3 n m p = n+m+p
+  zero       = 0
+
+instance AddThree a => AddThree [a] where
+  add3 = zipWith3 add3
+  zero = repeat zero
+
+-- Combine elementwise (i.e. zipWith3) the three lists:
+--
+--	 z,a0,a1,a2,...
+--	a0,a1,a2,...,an
+--      a1,a2,...,an,z
+--
+-- using the ternary function f
+-- Example: f is addition of three numbers, z is zero.
+
+zipOffset3 :: (a -> a -> a -> a) -> a -> [a] -> [a]
+
+zipOffset3 f z xs = zipWith3 f (z:xs) xs (tail xs ++ [z])
+
+-- From the grid of occupation (Boolean) calculate the
+-- number of occupied adjacent squares.
+-- Note that the stone in the square itself is also
+-- counted.
+
+countConfig :: [[Bool]] -> [[Int]]
+
+countConfig = addOffset . map addOffset . makeNumeric
+
+-- A variant of countConfig which doesn't count the stone in
+-- the square itself.
+
+countConfigLess :: [[Bool]] -> [[Int]]
+
+countConfigLess bs 
+  = zipWith (zipWith (-)) (countConfig bs) (makeNumeric bs)
+
+-- Boolean matrix to numeric matrix; True to 1, 
+-- False to 0.
+
+makeNumeric :: [[Bool]] -> [[Int]]
+
+makeNumeric = map (map (\b -> if b then 1 else 0))
+
+-- A 3*3 Boolean test matrix.
+
+test1 = [[True, False, True],[True,True,True],[False,True,True]]
+
+-- Printing the grid
+
+showGrid :: [[Int]] -> String
+
+showGrid nss = "   " ++ take (length (head nss)) ['a' .. 'z'] ++ "\n" ++
+             concat (zipWith f [0 .. length nss - 1] nss)
+	     where
+	     f n ns = pad 3 (show n) ++ concat (map show ns) ++ "\n"
+
+pad :: Int -> String -> String
+
+pad n st
+  | len <= n		= st ++ replicate (n - len) ' ' 
+  | otherwise		= take n st
+    where
+    len = length st
+
+-- Strength of the product functor on the left
+
+appLeft :: (a -> b) -> (a,c) -> (b,c)
+
+appLeft f (x,y) = (f x , y)
+
+-- Update list xs at index n to have value f (xs!!n)
+-- Handles out of range indices
+	     
+update :: Int -> (a -> a) -> [a] -> [a]
+
+update n f xs = front ++ rear
+		where
+		(front,rest) = splitAt n xs
+		rear = case rest of
+			[]	-> []
+			(h:t)	-> f h:t
+			
+-- Update an array to have value x at position (n,m)			
+ 
+updateArray :: Point -> a -> [[a]] -> [[a]]
+
+updateArray (n,m) x xss = update n (update m (const x)) xss
+
+-- Show play
+-- Assumes that the two arrays are of the same shape
+-- The second array gives the adjacency count of the cell,
+-- whilst the first indicates whether or not it is uncovered.
+
+
+showPlay :: [[Bool]] -> [[Bool]] -> [[Int]] -> String
+
+showPlay ess mss nss 
+           = "\n   " ++ take (length (head nss)) ['a' .. 'z'] ++ "\n" ++
+             concat (zipWith4 f [0 .. length nss - 1] ess mss nss) ++"\n"
+	     where
+	     f n es ms ns 
+	       = pad 3 (show n) ++ concat (zipWith3 showCell es ms ns) ++ "\n"
+
+-- How to show the value in a particular cell.
+
+showCell :: Bool -> Bool -> Int -> String
+
+showCell showing marked n 
+	= if marked then "X"
+	     else if not showing then "."
+                 else if n==0 then " "
+		     else show n
+
+
+-- Play the game; pass in the number of mines
+-- and the (square) board size as initial arguments.
+
+playGame :: Int -> Int -> IO ()
+
+playGame mines size = 
+   playGameGrid grid count showing marked
+
+   where
+
+   grid      = randomGrid mines size size
+   count     = countConfig grid			
+   showing   = map (map (const False)) grid
+   marked    = map (map (const False)) grid
+   
+playGameGrid :: [[Bool]] -> [[Int]] -> [[Bool]] -> [[Bool]] -> IO ()
+
+playGameGrid grid count showing marked =
+     do { putStr (showPlay showing marked count) ;
+          (choice,point) <- getInput size ;
+	  case choice of
+	    'q' -> return ()
+	    'h' -> do { putStr helpInfo ; playGameGrid grid count showing marked }
+	    'm' -> playGameGrid grid count showing (updateArray point True marked)
+	    'u' -> playGameGrid grid count showing (updateArray point False marked)
+	    'r' -> if grid!!!point 
+	             then (do { putStr "\nLOST!" ; return () })
+	             else
+	                (playGameGrid grid count 
+			              (uncoverClosure count point showing)
+	                              marked)
+	    's' -> let {eqs = getInfo count showing marked point;
+	                normEqs = fixSplit eqs }
+		   in do { putStr $ showEquations eqs ; 
+	                   putStr "---------\n" ;
+	                   putStr $ showEquations normEqs ;
+	                   playGameGrid grid count showing marked }
+	    'a' -> let {eqs = fixSplit (getInfo count showing marked point);
+	                (newShow,newMark) = playAutoOne grid count
+						showing marked point}
+		   in do {
+	                putStr $ showEquations eqs ;
+			playGameGrid grid count newShow newMark }
+	    't' -> playAuto grid count showing marked [point]
+	    _   -> playGameGrid grid count showing marked 
+	}
+	where size = length grid
+
+-- A uniform procedure for getting input, which gives
+-- a choice and a cell. 
+-- In the case that cell information is not required, i.e.
+-- 'help' or 'quit' a dummy point is returned.
+-- Parameterised by the size of the grid, so that the Point
+-- returned is quaranteed to be in the grid ... primitive
+-- error correction.
+
+getInput :: Int -> IO (Char,Point)
+
+getInput size =
+  do {    choice <- getChar ;
+	  if elem choice "smurat"	-- need to get (row,col)
+	  then 
+	   do {
+           rowCh <- getChar ;				-- get row
+	   colCh <- getChar ;				-- and column
+	   let { row = fitRange size (fromEnum rowCh - fromEnum '0') } ; 
+	   let { col = fitRange size (fromEnum colCh - fromEnum 'a') } ;
+	   let { point = (row,col) } ;
+	   return (choice,point)
+	      }
+	  else 				-- dummy values for (row,col) 
+	  do {
+	   let { dummy = (0,0) } ;
+	   return (choice,dummy)
+	      }
+     }
+
+helpInfo :: String
+
+helpInfo
+  = "\n\n q\tQuit\n\
+    \ h\tHelp information\n\
+    \ m7b\tMark position 7b\n\
+    \ u7b\tUnmark position 7b\n\
+    \ r7b\tReveal position 7b\n\
+    \ s7b\tShow equations at 7b\n\
+    \ a7b\tAutomatic turn at 7b\n\
+    \ t7b\tTransitive automatic from 7b\n\n"
+	
+-- Play one step automatically
+
+playAutoOne :: [[Bool]] -> [[Int]] -> [[Bool]] -> [[Bool]] -> 
+               Point -> ([[Bool]],[[Bool]])
+
+playAutoOne grid count showing marked point
+ = let eqs = fixSplit (getInfo count showing marked point)
+   in (updateShowByEqs eqs count showing,
+       updateMarkByEqs eqs marked)
+
+-- Play the game automatically from the information at point (n,m)
+-- Halts when no further progress made, and calls playGame.
+
+playAuto :: [[Bool]] -> [[Int]] -> [[Bool]] -> [[Bool]] -> [Point] -> IO ()
+
+playAuto grid count showing marked []
+  = playGameGrid grid count showing marked
+playAuto grid count showing marked (point:rest)
+ = let eqs = fixSplit (getInfo count showing marked point)
+       (newShow,newMark) = playAutoOne grid count showing marked point
+       newPts = makeNeg eqs ++ makePos eqs
+   in if (showing,marked)==(newShow,newMark) 
+   then playAuto grid count showing marked rest
+   else 
+   do { putStr $ showEquations eqs ;
+        putStr (showPlay showing marked count) ;
+	playAuto grid count newShow newMark (nub(newPts++rest)) }
+
+
+-- Finding the closure of a point / set of points.
+-- The worker functions: doClosure, doClosureList, carry around a 
+-- list of points already visited.
+
+closure :: [[Int]] -> Point -> [Point]
+
+closure count point = doClosure count point []
+
+-- doClosure, doClosureList use a variant of the algorithm 
+-- on pp333-4 of craft2e.
+
+doClosure :: [[Int]] -> Point -> [Point] -> [Point]
+
+doClosure count point avoid
+  | count!!!point /= 0	= [point]
+  | otherwise	
+    = point : doClosureList count nbs (point:avoid)
+      where
+      nbs = nbhrs count point
+
+doClosureList :: [[Int]] -> [Point] -> [Point] -> [Point]
+
+doClosureList count [] avoid = []
+
+doClosureList count (point: points) avoid
+  = next ++ doClosureList count points (avoid ++ next)
+    where
+    next = if elem point avoid
+           then [point]
+	   else doClosure count point avoid
+
+-- Uncover all the points in the closure
+
+uncoverClosure :: [[Int]] -> Point -> [[Bool]] -> [[Bool]]
+
+uncoverClosure count point 
+  = foldr (.) id $ 
+    map (flip updateArray True) (closure count point)
+
+-- What are the neighbours of a point?
+
+nbhrs :: [[Int]] -> Point -> [Point]
+
+nbhrs count (p,q)
+  = filter inGrid [ (p-1,q-1), (p-1,q), (p-1,q+1),
+                    (p,q-1),   (p,q),   (p,q+1),
+		    (p+1,q-1), (p+1,q), (p+1,q+1) ]
+    where
+    inGrid (s,t) = 0<=s && s <= rows &&
+                   0<=t && t <= cols
+    rows = length count - 1
+    cols = length (head count) -1
+
+-- Push an integer value into the range 
+--	0 .. r-1
+
+fitRange :: Int -> Int -> Int
+
+fitRange r val
+  | 0<=val && val<r	= val
+  | val<0		= 0
+  | val>=r 		= r-1
+
+-- Array lookup operation
+
+(!!!) :: [[a]] -> Point -> a
+
+xss!!!(p,q) = xss!!p!!q
+
+-- Showing the information about a given cell,
+-- in the context of certain known information:
+--	count showing marked
+-- Produces an equation corresponding to each neighbour
+-- which has its value showing.
+-- Count zero for showing zeroes and 1 for marked cells
+-- i.e. assumes that markings are correct.
+
+-- Refactored as getInfoCell below ....
+
+getInfo :: [[Int]] -> [[Bool]] -> [[Bool]] -> Point -> Equations
+
+getInfo count showing marked point
+  = map (getInfoCell count showing marked)
+        [ nb | nb <- nbhrs count point , showing!!!nb ]
+
+showInfo :: [[Int]] -> [[Bool]] -> [[Bool]] -> Point -> String
+
+showInfo count showing marked point 
+  = showEquations (getInfo count showing marked point)
+			  
+type Equations = [Equation]
+type Equation  = (Int, [Point])
+
+-- Initial program for the information extracts it and immediately
+-- shows it. Subsequently refactored to produce a data structure
+-- containing the information, and a corresponding show function over
+-- the data structure.
+
+-- Call this separate producer and consumer ... allows whatever is
+-- produced to be used in more than one way.
+-- Can envisage the converse too: merging producer and consumer,
+-- particularly if there's only one use of the producer in the program.
+
+getInfoCell :: [[Int]] -> [[Bool]] -> [[Bool]] -> Point -> Equation 
+
+getInfoCell count showing marked point
+  = ( (count!!!point - marks) , 
+      [ nb | nb <- nbrs, not (showing!!!nb), not (marked!!!nb) ]
+    )
+    where 
+    nbrs              = nbhrs count point
+    marks             = sum [ 1 | nb<-nbrs , marked!!!nb ]
+
+-- Showing the information in a cell
+    
+showInfoCell :: [[Int]] -> [[Bool]] -> [[Bool]] -> Point -> String 
+
+showInfoCell count showing marked point
+  = showEquation (getInfoCell count showing marked point)
+
+showEquations :: Equations -> String
+
+showEquations = ("\n"++) . concat . (map showEquation)
+
+showEquation :: Equation -> String
+
+showEquation (lhs, rhs) 
+  = show lhs ++ " = " ++ showPoints rhs ++ "\n"
+
+showRow :: Int -> String
+showRow           = show
+
+showCol :: Int -> String
+showCol t         = [ toEnum (t + fromEnum 'a') ]
+
+showPoint :: Point -> String
+showPoint (p,q)   = showRow p ++ showCol q
+
+showPoints :: [Point] -> String
+showPoints []     = "none"
+showPoints [p]    = showPoint p
+showPoints (p:ps) = showPoint p ++ " + " ++ showPoints ps
+
+-- Reducing a list of equations to a normal form
+
+-- Is one list a sublist of the other?
+-- It is assumed that the elements appear in the same order, 
+-- without repetitions.
+
+subList :: Eq a => [a] -> [a] -> Bool
+
+subList [] _     = True
+subList (_:_) [] = False
+subList (x:xs) (y:ys)
+  | x==y	= subList xs ys
+  | otherwise	= subList (x:xs) ys
+
+-- The difference of two lists;
+-- only applied when the first is a subList of the second.
+
+listDiff :: Eq a => [a] -> [a] -> [a]
+
+listDiff [] ys	= ys
+listDiff (_:_) [] = error "listDiff applied to non-subList"
+listDiff (x:xs) (y:ys) 
+  | x==y	= listDiff xs ys
+  | otherwise	= y : listDiff (x:xs) ys
+
+-- Only splits when the first rhs is a sublist of the second
+-- and a proper sublist at that.
+
+splitEq :: Equation -> Equation -> Equation
+
+splitEq e1@(l1,r1) e2@(l2,r2)
+  | e1==e2		= e2
+  | subList r1 r2	= (l2-l1 , listDiff r1 r2)
+  | otherwise		= e2
+
+
+-- Split a set (list) of equations
+
+splitEqs :: [Equation] -> [Equation]
+
+splitEqs eqs
+  = foldr (.) id (map map (map splitEq eqs)) eqs
+
+-- Generic fixpt operator
+
+fixpt :: Eq a => (a -> a) -> a -> a
+
+fixpt f x
+  = g x
+    where
+    g y
+  	| y==next	= y
+  	| otherwise	= g next
+    	  where
+	  next = f y
+
+fixSplit :: [Equation] -> [Equation]
+
+fixSplit = fixpt (nub.splitEqs)
+
+-- Added in Minesweeper3 ...
+
+-- Is an equation determinate?
+-- Could be determinate in setting all values to
+-- zero (deterNeg) or to one (deterPos)
+
+determined :: Equation -> Bool
+
+determined eq
+  = deterPos eq || deterNeg eq
+  
+deterPos,deterNeg :: Equation -> Bool
+
+deterPos (n,pts)
+  = n>0 && n==length pts
+
+deterNeg (n,pts) 
+  = n==0 && length pts > 0
+
+-- Find all the points to be made negative or positive
+-- from a set of Equations.
+
+makePos,makeNeg :: [Equation] -> [Point]
+
+makeNeg = nub . concat . map snd . filter deterNeg
+makePos = nub . concat . map snd . filter deterPos
+
+-- Update a marking array according to the information 
+-- in a set of equations.
+
+updateMarkByEqs :: [Equation] -> [[Bool]] -> [[Bool]]
+
+updateMarkByEqs eqs marked
+  = updatePos marked
+    where
+    updatePos = foldr (.) id $ map updateP (makePos eqs)
+    updateP pt = updateArray pt True 
+
+-- Update a showing array according to the info
+-- in a set of equations. In the first version it
+-- failed to uncover the closure of the uncovered points.
+-- To do this, it has to be passed the grid count as well
+-- as the show matrix.
+
+updateShowByEqs :: [Equation] -> [[Int]] -> [[Bool]] -> [[Bool]]
+
+updateShowByEqs eqs count showing
+  = updateNeg showing
+    where
+    updateNeg = foldr (.) id $ map updateN (makeNeg eqs)
+    updateN   = uncoverClosure count
+
+
+    
+ Palindromes/Palin.hs view
@@ -0,0 +1,55 @@++------------------------------------------------------------------+--								--+--	Solution to the palindrome problem			--+--								--+--	(c) Simon Thompson, University of Kent, 1997-2011       --+--                                                              --+------------------------------------------------------------------++module Palin where++import Data.Char++palin :: String -> Bool++palin st = simplePalin (disregard st)++simplePalin :: String -> Bool++simplePalin st = (rev st == st)++rev :: String -> String++rev []	   = []+rev (a:st) = rev st ++ [a]++disregard :: String -> String++disregard = change . remove++remove :: String -> String+change :: String -> String++remove []	= []+remove (a:st) +  | notPunct a  = a : remove st   +  | otherwise   =     remove st	++notPunct ch = isAlpha ch || isDigit ch++change []	= []+change (a:st) = convert a : change st++convert :: Char -> Char++convert ch +  | isCap ch      = toEnum (fromEnum ch + offset)+  | otherwise     = ch+    where+    offset = fromEnum 'a' - fromEnum 'A'++isCap :: Char -> Bool++isCap ch = 'A' <= ch && ch <= 'Z'+
− Test.hs
@@ -1,78 +0,0 @@-module Test where  --import PicturesSVG-    -ex :: Integer-ex = 3+4--double :: Integer -> Integer-double x = 2*x--trip :: Integer -> Integer-trip y = 3*y--pic1 :: Picture-pic1 = horse `beside` flipV (invert horse)--pic2 :: Picture-pic2 = pic1 `above` invert pic1--howManyEqual :: Integer -> Integer -> Integer -> Integer--howManyEqual x y z -  | x==y && y==z            = 3-  | x==y || y==z || z==x    = 2-  | otherwise               = 0---(^^^) :: Integer -> Integer -> Integer-x ^^^ y -    | x>= y      = x-    | otherwise  = y--fac :: Integer -> Integer--fac 0               = 1-fac n -    | n>0           = n * fac (n-1)-    | otherwise     = 0----maxThreeOccurs :: Integer -> Integer -> Integer -> (Integer,Integer)--maxThreeOccurs x y z =-  (theMax,occurs)-  where-    theMax = max (max x y) z-    occurs = eq x + eq y + eq z-    eq w = if w==theMax then 1 else 0--pow :: Integer -> Integer--pow n -  | n==0      = 1-  | n>0       = 2 * pow (n-1) -  | otherwise = 0      --sumFun :: (Integer -> Integer) -> Integer -> Integer-  -sumFun f n -  | n==0      = f 0-  | n>0       = sumFun f (n-1) + f n-  | otherwise = 0  ---fibP :: Integer -> (Integer,Integer)--fibP 0 = (0,1)-fibP n = (v,u+v)-         where-         (u,v) = fibP (n-1)---fib :: Integer -> Integer--fib 0 = 0-fib 1 = 1-fib n = fib (n-2) + fib (n-1)
svgOut.xml view
@@ -7,7 +7,7 @@    <image x="0" y="0" width="150" height="200" xlink:href="blk_horse_head.jpg"/> -  <image x="150" y="0" width="150" height="200" xlink:href="blk_horse_head.jpg" transform="translate(450,0) scale(-1,1)"  filter="url(#negative)"/>+  <image x="150" y="0" width="150" height="200" xlink:href="blk_horse_head.jpg" transform="translate(450,0) scale(-1,1)" />  </svg>