{-- Examples from Monad lecture. Thanks to Andrew Tolmach for the examples. The outline is drawn from "Monad for Functional Programming" by Phil Wadler. --} import IO import Control.Monad.ST.Lazy import Data.STRef.Lazy import Data.Array.ST import Data.Array import Control.Monad echo :: IO () echo = do { b <- isEOF; if not b then do { x <- getChar; putChar x; echo } else return () } data Exp = Plus Exp Exp | Minus Exp Exp | Times Exp Exp | Div Exp Exp | Const Int deriving (Show) expA = (Div (Const 3) (Plus (Const 4) (Const 2))) buggyExpA = Plus (Const 4) (Div (Const 2) (Const 0)) buggyExpB = (Div (Plus (Const 4) (Const 2)) (Times (Const 0) (Const 10))) {-- Original, simple interpreter --} eval :: Exp -> Int eval (Plus e1 e2) = (eval e1) + (eval e2) eval (Minus e1 e2) = (eval e1) - (eval e2) eval (Times e1 e2) = (eval e1) * (eval e2) eval (Div e1 e2) = (eval e1) `div` (eval e2) eval (Const i) = i answerA = eval expA answerBugA = eval buggyExpA answerBugB = eval buggyExpB -- Suppose we want to improve this code by trapping attempts to divide by zero. data Hopefully a = Ok a | Error String deriving (Show) {-- Original interpreter extended to check for division by zero. --} eval1 :: Exp -> Hopefully Int eval1 (Plus e1 e2) = case eval1 e1 of Ok v1 -> case eval1 e2 of Ok v2 -> Ok (v1 + v2) Error s -> Error s Error s -> Error s eval1 (Minus e1 e2) = case eval1 e1 of Ok v1 -> case eval1 e2 of Ok v2 -> Ok (v1 - v2) Error s -> Error s Error s -> Error s eval1 (Times e1 e2) = case eval1 e1 of Ok v1 -> case eval1 e2 of Ok v2 -> Ok (v1 * v2) Error s -> Error s Error s -> Error s eval1 (Div e1 e2) = case eval1 e1 of Ok v1 -> case eval1 e2 of Ok v2 -> if v2 == 0 then Error "divby0" else Ok (v1 `div` v2) Error s -> Error s Error s -> Error s eval1 (Const i) = Ok i answer1A = eval1 expA answerBug1A = eval1 buggyExpA answerBug1B = eval1 buggyExpB {-- This solution exposes a lot of ugly plumbing. Every time an expression evalutes to Error, the Error propagates to the final result. We can abstract this behavior to a higher-order function. --} ifOKthen :: Hopefully a -> (a -> Hopefully b) -> Hopefully b e `ifOKthen` k = case e of Ok x -> k x Error s -> Error s {-- Interpreter that uses the `ifOKthen` combinator --} eval2 :: Exp -> Hopefully Int eval2 (Plus e1 e2) = eval2 e1 `ifOKthen` (\v1 -> eval2 e2 `ifOKthen` (\v2 -> Ok(v1 + v2))) eval2 (Minus e1 e2) = eval2 e1 `ifOKthen` (\v1 -> eval2 e2 `ifOKthen` (\v2 -> Ok(v1 - v2))) eval2 (Times e1 e2) = eval2 e1 `ifOKthen` (\v1 -> eval2 e2 `ifOKthen` (\v2 -> Ok(v1 * v2))) eval2 (Div e1 e2) = eval2 e1 `ifOKthen` (\v1 -> eval2 e2 `ifOKthen` (\v2 -> if v2 == 0 then Error "divby0" else Ok(v1 `div` v2))) eval2 (Const i) = Ok i answer2A = eval2 expA answerBug2A = eval2 buggyExpA answerBug2B = eval2 buggyExpB {-- Compare the type of `isOKthen` with the type of >>= ifOKthen :: Hopefully a -> (a -> Hopefully b) -> Hopefully b (>>=) :: IO a -> (a -> IO b) -> IO b and the type of Ok with the type of return Ok :: a -> Hopefully a return :: a -> IO a This similarity isn't accidental. Like IO, Hopefully with ifOKthen and Ok forms a monad. --} {-- The standard prelude defines a type class for monads. We can use it to tell the system that Hopefully is a monad. This allows us to use a library of operations that work over any moand. And, it enables us to use the "do" notation for Hopefully just as we did for IO --} instance Monad Hopefully where return = Ok (>>=) = ifOKthen {-- Monadic error-checking interpreter --} eval3 :: Exp -> Hopefully Int eval3 (Plus e1 e2) = do { v1 <- eval3 e1; v2 <- eval3 e2; return (v1 + v2) } eval3 (Minus e1 e2) = do { v1 <- eval3 e1; v2 <- eval3 e2; return (v1 - v2) } eval3 (Times e1 e2) = do { v1 <- eval3 e1; v2 <- eval3 e2; return (v1 * v2) } eval3 (Div e1 e2) = do { v1 <- eval3 e1; v2 <- eval3 e2; if v2 == 0 then Error "divby0" else return (v1 `div` v2)} eval3 (Const i) = return i answer3A = eval3 expA answerBug3A = eval3 buggyExpA answerBug3B = eval3 buggyExpB {-- Suppose we wanted to modify our original evaluator to record a trace of its ops. --} evalT :: Exp -> [String] -> ([String], Int) evalT (Plus e1 e2) s = let (s1,v1) = evalT e1 s (s2,v2) = evalT e2 s1 in (s2++["+"], v1 + v2) evalT (Minus e1 e2) s = let (s1,v1) = evalT e1 s (s2,v2) = evalT e2 s1 in (s2++["-"], v1 - v2) evalT (Times e1 e2) s = let (s1,v1) = evalT e1 s (s2,v2) = evalT e2 s1 in (s2++["*"], v1 * v2) evalT (Div e1 e2) s = let (s1,v1) = evalT e1 s (s2,v2) = evalT e2 s1 in (s2++["/"], v1 `div` v2) evalT (Const i) s = (s++[show i], i) (traceTA,anwerTA) = evalT expA [] -- (["3","4","2","+","/"],0) {- In an imperative language, it would be more convenient to store trace in a global variable. In Haskell, we can use a tracing moad. -} data Tr a = Tr [String] a instance Monad Tr where return a = Tr [] a m >>= k = let (trace, a) = runTr m (trace', b) = runTr (k a) in Tr (trace++trace') b -- This function lets us "run" the Trace monad runTr :: Tr a -> ([String], a) runTr (Tr s a) = (s,a) -- This function adds x to the trace trace :: String -> Tr () trace x = Tr [x] () {-- Monadic tracing interpreter --} evalTM :: Exp -> Tr Int evalTM (Plus e1 e2) = do { v1 <- evalTM e1; v2 <- evalTM e2; trace "+"; return (v1 + v2) } evalTM (Minus e1 e2) = do { v1 <- evalTM e1; v2 <- evalTM e2; trace "-"; return (v1 - v2) } evalTM (Times e1 e2) = do { v1 <- evalTM e1; v2 <- evalTM e2; trace "*"; return (v1 * v2) } evalTM (Div e1 e2) = do { v1 <- evalTM e1; v2 <- evalTM e2; trace "/"; return (v1 `div` v2) } evalTM (Const i) = do{trace (show i); return i} answerTM = runTr (evalTM expA) -- (["3","4","2","+","/"],0) {-- Count the number of divisions during evaluation. Doing this non-monadically requires changes similar to the trace changes, where an integer variable is threaded through all the computation. To do this monadically, we'll introduce a State monad. The structure of this monad is very similar to the structure of the IO monad, in that an action takes a "state" (world) as input and returns a value as well as a modified "state" (world). The Prelude The type constructor ST is defined in Control.Monad.ST.Lazy, so to show the code here, we'll use the name State istead. --} data State s a = ST {runST' :: s -> (a,s)} {-- Newtype is just like a datatype except . it can only have one constructor . its constructor can have only one argument . it describes a strict isomorphism between types . it can be implemented more efficiently that the corresponding datatype -- The curly braces and the label :: defien a record with a single field. . the name of the field serves as a deconstructor for the type, so . runST' :: State s a -> s -> (s,a) . This function is called "runST'" because it will corresponds to "running" the action of the monad. --} instance Monad (State s) where return a = ST (\s -> (a,s)) -- think about the pipe diagram for IO return m >>= k = ST (\s -> let (a,s') = runST' m s in runST' (k a) s') -- Get the value of the state, leave state value unchanged get :: State s s get = ST (\s -> (s,s)) -- make put's argument the new state, return the unit value put :: s -> State s () put s = ST (\_ -> ((),s)) -- before update, the state has value s. -- return s, replace s with f s. update :: (s->s) -> State s s update f = ST (\s -> (s, f s)) {-- Monadic interpreter that counts the number of divisions. --} evalCD :: Exp -> State Int Int evalCD (Plus e1 e2) = do { v1 <- evalCD e1; v2 <- evalCD e2; return (v1 + v2) } evalCD (Minus e1 e2) = do { v1 <- evalCD e1; v2 <- evalCD e2; return (v1 - v2) } evalCD (Times e1 e2) = do { v1 <- evalCD e1; v2 <- evalCD e2; return (v1 * v2) } evalCD (Div e1 e2) = do { v1 <- evalCD e1; v2 <- evalCD e2; update (+1); return (v1 `div` v2) } evalCD (Const i) = do{return i} -- The second component is the desired answer as it is the final "state". answerCD = runST' (evalCD expA) 0 -- (0,1) {-- End of interpreter example --} -- Functions for allocating imperative variables in s {-- From Data.STRef.Lazy data STRef s a newSTRef :: a -> ST s (STRef s a) readSTRef :: STRef s a -> ST s a writeSTRef :: STRef s a -> a -> ST s () modifySTRef :: STRef s a -> (a -> a) -> ST s () --} swap :: STRef s a -> STRef s a -> ST s () swap r1 r2 = do {v1 <- readSTRef r1; v2 <- readSTRef r2; writeSTRef r1 v2; writeSTRef r2 v1} testSwap :: Int testSwap = runST (do { r1 <- newSTRef 1; r2 <- newSTRef 2; swap r1 r2; readSTRef r2}) -- 1 type Vertex = Char type Graph = Array Vertex [Vertex] data Tree a = Node a [Tree a] aGraph = listArray ('a','e') [['b','c'], [],['d'],['e'],[]] dfs :: Graph -> [Vertex] -> [Tree Vertex] dfs g vs = runST( do{ marks <- newArray (bounds g) False; search marks vs}) where search :: STArray s Vertex Bool -> [Vertex] -> ST s [Tree Vertex] search marks [] = return [] search marks (v:vs) = do { visited <- readArray marks v; if visited then search marks vs else do { writeArray marks v True; ts <- search marks (g!v); us <- search marks vs; return ((Node v ts) : us) } } toPreOrder :: [Tree Vertex] -> [Vertex] toPreOrder [] = [] toPreOrder (t:ts) = (toOrder t) ++ (toPreOrder ts) where toOrder :: Tree Vertex -> [Vertex] toOrder (Node n ts) = n:(join(map toOrder ts)) reachable :: Graph -> Vertex -> Vertex -> Bool reachable g a b = b `elem` (toPreOrder ( dfs g [a])) testReachable = reachable aGraph 'a' 'c' {-- A monad of non-determinism. Like many other algebraic types, lists form a monad The instance declaration for monad [] is part of the prelude. return :: a -> [a] (>>=) :: [a] -> (a -> [b]) -> [b] instance Monad [ ] where return x = [x] [] >>= f = [] (x:xs) >>= f = f x ++ (xs >>= f) With lazy evaluation, we can view this monad as a representation of non-deterministic computations. Each item in the list corresponds to one possible outcome. --} orelse = (++) bad = [] multiplyTo :: Int -> [(Int,Int)] multiplyTo n = do { x <- [1..n]; y <- [x..n]; if (x * y == n) then return (x,y) else bad } fstMult = head (multiplyTo 10) sndMult = head (tail (multiplyTo 10)) type Row = Int type Col = Int type QPos = (Row,Col) type Board = [QPos] safe :: QPos -> QPos -> Bool safe (r,c) (r',c') = r /= r' && c /= c' && (abs(r-r') /= abs(c-c')) pick :: Int -> [Int] pick 0 = bad pick n = return n `orelse` pick (n-1) add :: QPos -> Board -> [Board] add q qs | all (safe q) qs = return (q:qs) | otherwise = bad nqueens :: Int -> [Board] nqueens n = fill_row 1 [] where fill_row r board | r > n = return board | otherwise = do { c <- pick n; board' <- add (r,c) board; fill_row (r+1) board'; } queenResult = head (nqueens 8) -- [(8,5),(7,7),(6,2),(5,6),(4,3),(3,1),(2,4),(1,8)] data BTree a = Leaf a | BNode (BTree a) (BTree a) deriving (Show) instance Monad BTree where return x = Leaf x Leaf x >>= f = f x BNode tl tr >>= f = BNode (tl>>=f) (tr>>=f) aTree = BNode (Leaf 3) (BNode (Leaf 4) (Leaf 5)) anf :: Int -> BTree Int anf i = Leaf (i+1) testTreeMonad = aTree >>= anf -- sequence' because sequence is in Prelude sequence' [] = return [] sequence' (m:ms) = do{ a <- m; as<-sequence' ms; return (a:as) } testSequence = sequence' [getChar, getChar, getChar] putGetChar c = putChar c >> getChar mapM' f as = sequence(map f as) mapMUse = mapM' putGetChar "abc"