This is a continuation of the previous lecture (Lecture 16).
During last lecture we made stateful structures for the Fibonacci function, but we need something more general so that we can use state for other problems.
That's where Monads come in.
Here's the definition of the Monad Typeclass:
class Applicative m => Monad m where
(>>=) :: m a -> (a -> m b) -> m b -- bind
pure :: a -> m aNote: the real name of the second function is not
pure, it is actuallyreturn. Most Haskell users agree that naming itreturnwas a huge mistake by the designers of Haskell.
module FibMonad where
data FibState = FibState {
previousNumber :: Integer,
previousPreviousNumber :: Integer,
currentNumber :: Integer
}
-- FibMonad is the same as FibStateful
data FibMonad a = FibMonad {
runFib :: FibState -> (FibState, a)
}
instance Monad FibMonad where
-- (>>=) :: m a -> (a -> m b) -> m b -- bind
(FibMonad f) >>= g = FibMonad (\oldstate ->
let (newstate, value) = f oldstate
FibMonad rg = (g value)
in rg newstate)
-- pure :: a -> m a
pure x = FibMonad (\s -> (s, x))
getFibState :: FibMonad FibState
getFibState = FibMoad (\s -> (s, s))
setFibState :: FibState -> FibMonad ()
setFibState newstate = FibState (\s -> (newstate, ()))
getPreviousNumber :: FibMonad Integer
getPreviousNumber =
getFibState >>= \s -> pure (previousNumber s)
setPreviousNumber :: Integer -> FibMonad ()
setPreviousNumber i =
getFibState >>= \s -> setFibState newstate
where newstate = FibState {
previousNumber = i,
previousPreviousNumber = previousPreviousNumber s,
currentNumber = currentNumber s
}
-- Add other getters and setters here
doFibMonad :: FibState -> FibMonad a -> a
doFibMonad initialState gm =
let (finalstate, result) = (runFib gm) initialState
in result-- bind
(>>=) :: Monad m => m a -> (a -> m b) -> m b
-- alternative bind
(>>) :: Monad m => m a -> m b -> m bThe second parameter of << does not need an input parameter. This is perfect for binding to our getter functions.
<- is similar to an assignment operator. We can use it after a do
fibAlgorithm n =
repeatTimes n (
do pn <- getPreviousNumber
setPreviousPreviousNumber pn
cn <- getCurrentNumber
setPreviousNumber cn
newpn <- getPreviousNumber
newppn <- getPreviousPreviousNumber
setCurrentNumber (newpn + newppn)
getCurrentNumber
)IO is a monad
-- hello.hs
main :: IO()
main = putStrLn "Hello World"Then we can use compile the program using:
ghc hello.hs
main :: IO ()
main = do "Enter a file name: "
-- gets input from the stdin
filename <- getLine
filecontent <- readFile "helloworld.hs"
let firstchar = head filecontent
print firstcharput is for our setters.
get is for our getters.
evalState starts the function with initial state.
import Control.Monad.State
import Control.Monad (forM)
fib:: Int -> Int
fib = evalState (
do forM [1..n] (\_ ->
do (a,b) <- get
put (b, a+b))
(a, b) <- get
pure b
)
) (0, 1)
newSTRefreadSTRef
Understand the bind function and the pure function (actually named return)
#school/f19/proglang-f19