haskell-course

IO and its interfaces

fmap, (<$>) :: (a -> b) -> IO a -> IO b
pure, return :: a -> IO a
(<*>) :: IO (a -> b) -> IO a -> IO b 
(>>=) :: IO a -> (a -> IO b) -> IO b
class Functor f => Applicative f
class Applicative m => Monad m

Chaining Lookups

phonebook :: [(String, String)]
phonebook = [ ("Bob",   "01788 665242"),
              ("Fred",  "01624 556442"),
              ("Alice", "01889 985333"),
              ("Jane",  "01732 187565") ]

registrationID :: [(String, Int)]
registrationID = [ ("01788 665242", 1)
                 , ("01624 556442", 2)
                 , ("01889 985333", 3)
                 ]

moneyOwed :: [(Int, Double)]
moneyOwed = [   (1, 200.0)
            ,   (2, 60.0)
            ,   (4, 100.0)
            ]
lookup :: Eq a => a -> [(a, b)] -> Maybe b
nameToMoney :: String -> Maybe Double
nameToMoney name =
    case lookup name phonebook of
        Nothing -> Nothing
        Just num -> case lookup num registrationID of
            Nothing -> Nothing 
            reg -> lookup reg moneyOwed
chainMaybe :: Maybe a -> (a -> Maybe b) -> Maybe b
chainMaybe Nothing _ = Nothing
chainMaybe (Just a) f = f a
nameToMoney :: String -> Maybe Double
nameToMoney name = 
    lookup name phonebook
    `chainMaybe` \num -> lookup num registrationID
    `chainMaybe` \reg -> lookup reg moneyOwed
(>>=) :: IO a -> (a -> IO b) -> IO b
(chainMaybe) :: Maybe a -> (a -> Maybe b) -> Maybe b
nameToMoney :: String -> Maybe Double
nameToMoney name = 
    lookup name phonebook
    >>= \num -> lookup num registrationID
    >>= \reg -> lookup reg moneyOwed
instance Functor Maybe where
    fmap f Nothing = Nothing
    fmap f (Just a) = Just (f a)

instance Applicative Maybe where
    pure a = Just a
    (Just f) (<*>) (Just x) = Just (f x)
instance Monad Maybe where
    (>>=) = chainMaybe
nameToMoney :: String -> Maybe Double
nameToMoney name = do
   num <- lookup name phonebook 
   reg <- lookup num registrationID
   lookup reg moneyOwed

Lists

concatMap :: (a -> [b]) -> [a] -> [b]
concatMap f xs = concat $ map f xs
knightMove :: (Int, Int) -> [(Int, Int)]
knightMove (x, y) = [ (x + i,  y + j) | i <- [-2, 2], j <- [-1, 1]]
                 ++ [ (x + i,  y + j) | i <- [-1, 1], j <- [-2, 2]]
knight2  (x, y) = concatMap knightMove $ knightMove (x, y)

After three moves

knight3 (x, y) = concatMap knightMove $ concatMap knightMove $ knightMove (x, y)
knight3 (x, y) = knightMove `concatMap` knightMove `concatMap` knightMove (x, y)
knight3 (x, y) = knightMove =<< knightMove =<< knightMove (x, y)

or

knight3 (x, y) = knightMove (x, y) >>= knightMove >>= knightMove
knight3 (x, y) = pure (x, y) >>= knightMove >>= knightMove >>= knightMove
triangles = [(a, b, c) | c <- [1..10], b <- [1..10], a <- [1..10]]

can be written as

triangles = do
    c <- [1..10]
    b <- [1..10]
    a <- [1..10]
    pure (a, b, c)
insert :: Int -> a -> [a] -> [a]
insert n x xs = take n xs ++ [x] ++ drop n xs

permutations :: [a] -> [[a]]
permutations [] = pure []
permutations (x:xs) = do
    n <- [0..length xs]
    xs' <- permutations xs
    pure $ insert n x xs'

You can also phrase this with concatMap.

State

Tree a = Nil | Node a (Tree a) (Tree a)
type Table a = [a]

findIndex :: Eq a => a -> Table a -> Maybe Int
findIndex x t = lookup x $ zip t [1..]

addToTable :: a -> Table a -> Table a
addToTable x = (++ [x])
abstractAux1 :: Eq a => Tree a -> State (Table a) (Tree Int)
abstractAux1 Nil = pure Nil
abstractAux1 (Node x t1 t2) = do
    curTable <- get
    n <- case findIndex x curTable of
        Just n' -> pure n'
        Nothing -> do
            let newTable = addToTable x curTable
            put newTable
            pure $ length newTable
    Node n <$> (abstractAux1 t1) <*> (abstractAux1 t2)
abstract :: Eq a => Tree a -> Tree Int
abstract t = evalState (abstractAux1 t) []
get :: State s s
put :: s -> State s ()
evalState :: State s a -> s -> a
newtype MyState s r = MyState {myRun :: s -> (s, r)}

myGet :: MyState s s
myGet = MyState $ \s -> (s, s)

myPut :: MyState s ()
myPut = MyState $ \s -> (s, ())

myEval :: s -> MyState s r -> r
myEval s ms = snd $ myRun ms s

instance Functor (MyState s) where
    fmap f ms = MyState $ \x -> let (s, r) = myRun ms x in (s, f r)

instance Applicative (MyState s) where
    pure a = MyState $ \s -> (s, a)
    sf <*> sa = MyState $ \s -> let (s', f) = myRun sf s
                                    (s'', a) = myRun sa s'
                                 in (s'', f a)

instance Monad (MyState s) where
    sa >>= f = MyState $ \s -> let (s', a) = myRun sa s in myRun (f a) s'