2.0 KiB
2.0 KiB
Monad Revision
You can think of a monad as a container for a data type
If M is a monad, that means an element of M: M_a is some sort of container where a is any datatype
One of the purposes of the do notation is to operate on the whole data structure by specifying operations that must apply to each of the elements in the data structure, without having to specify the whole structure.
M_a=\{x_1, x_2, x_3,...\}
do x <- m
let y = x ** 2 + 7
return y
This extracts an element of type a from m, squares and adds 7, and returns the new values as the data structure. Now M is
M_b=\{y_1, y_2, y_3, \ldots\}\\or\\M=\{x_1^2+7, x_2^2+7, x_3^2+7, \ldots\}
The above can be written as a functor
fmap (\x -> x**2+7) m
Monads have more functionality than functors though
If x is an element of a or x :: a
x :: a
return x
-- we can also write
pure x
Monads can have containers within containers
Assume we have a function makeBlob that maps every element of a to an element of M_b
makeBlob :: a -> Mb
makeBlob x1 = do x <- m
y <- makeBlob x
return y
-- this can be done instead with the bind operator
m >>= makeBlob
(>>=) :: Ma -> (a -> Mb) -> Mb
The IO Monad
square :: Int -> Int
square x = x*x
getInt :: IO Int
getInt = do putStrLn "Enter a number: "
s <- getLine -- getLine :: IO String
return (read s :: Int) --read :: String -> Int
squareIO :: IO Int
squareIO = do x <- getInt
let y <- square x
return y
-- as squareIO :: IO Int, returning y prints it out
squareIO :: IO () -- unit type, with only one element, also called ()
squareIO = do x <- getInt
let y <- square x
putStrLn("The square " ++ (show x) ++ " is " (show y))
return () --return unit type
-- in this case we dont even need return () as
-- putStrLn :: IO ()
--recursively asks for list unless 0 entered
getList :: IO [Int]
getList = do x <- getInt
if x == 0 then return []
else do
xs <- getList
return (x:xs)