You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The notes are written in an Org-mode file (notes_monads.org). A LaTeX file (notes_monads.tex) was automatically generated by Emacs 27.2 (Org mode 9.4.4). The working files (monads*.hs) mentioned in the notes are also included in this repository.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This document elaborates on the lectures on the topic of Monads imparted by Irfan Ali between May 27 and June 7, 2022.
Motivating example
Working file:monads1.hs
Following Philip Walder’s paperMonads for functional programming, we start with the implementation of the “calculator” data type Expr together with an “evaluation” function, eval, as follows:
dataExpr=ConInt
| AddExprExpr
| MulExprExpr
| DivExprExpreval'::Expr->Int
eval' (Con v) = v
eval' (Add e f) = eval' e + eval' f
eval' (Mul e f) = eval' e * eval' f
eval' (Div e f) = eval' e `div` eval' f
Note that both Expr and eval' are defined recursively.
Prelude> :l monads1.hs
[1 of 1] Compiling Main ( monads1.hs, interpreted )
Ok, one module loaded.
*Main>*Main> -- Example:
*Main> -- 2 * 3 + 4
*Main>*Main> eval' (Add (Mul (Con 2) (Con 3)) (Con 4))10'*Main> -- This throws an error:
*Main>*Main> eval' (Div (Con 3) (Con 0))*Exception: divide by zero
We now want to eliminate the exception error due to division by zero, so we define divSafe and evalSafe .
divSafe::Int->Int->MaybeInt
divSafe _ 0=Nothing
divSafe x y =Just (x `div` y)
evalSafe::Expr->MaybeInt
A naive declaration of evalSafe such as
evalSafe::Expr->MaybeInt
evalSafe (Con v) = v
evalSafe (Add e f) = evalSafe e + evalSafe f
evalSafe (Mul e f) = evalSafe e * evalSafe f
evalSafe (Div e f) = evalSafe e `divSafe` evalSafe f
would not work.
Problem: How to feed operators +, *, etc. with numbers. (Need to extract numbers out of ‘Maybe’.)
Now this works, but is too verbose:
evalSafe::Expr->MaybeInt
evalSafe (Con v) =Just v
evalSafe (Add e f) =case evalSafe e ofNothing->NothingJust e' ->case evalSafe f ofNothing->NothingJust f' ->Just (e' + f')
evalSafe (Mul e f) =case evalSafe e ofNothing->NothingJust e' ->case evalSafe f ofNothing->NothingJust f' ->Just (e' * f')
evalSafe (Div e f) =case evalSafe e ofNothing->NothingJust e' ->case evalSafe f ofNothing->NothingJust f' -> e' `divSafe` f'
Prelude> :r
[1 of 1] Compiling Main ( monads1.hs, interpreted )
Ok, one module loaded.
*Main>*Main> evalSafe (Div (Con 3) (Con 0))
Nothing
*Main>*Main> evalSafe (Add (Mul (Con 2) (Con 3)) (Con 4))
Just 10
To reduce complexity, we introduce:
return::a->Maybeareturn=Just(>>=)::Maybea-> (a->Maybeb) ->Maybeb
ma >>= k =case ma ofNothing->NothingJust a -> k a
Now, we can redefine ‘evalSafe’ in a consise manner:
eval::Expr->MaybeInt
eval (Con v) =return v
eval (Add e f) = eval e >>=\e' -> eval f >>=\f' ->return (e' + f')
eval (Mul e f) = eval e >>=\e' -> eval f >>=\f' ->return (e' * f')
eval (Div e f) = eval e >>=\e' -> eval f >>=\f' -> divSafe e' f'
and it works:
*Main> :r
[1 of 1] Compiling Main ( monads1.hs, interpreted )
Ok, one module loaded.
*Main>*Main>eval (Add (Mul (Con 2) (Con 3)) (Con 4))
Just 10
*Main>*Main>eval (Div (Con 3) (Con 0))
Nothing
Do notation
It is maybe clearer if we use the alternative formatting:
eval::Expr->MaybeInt
eval (Con v) =return v
eval (Add e f) =
eval e >>=\e' ->
eval f >>=\f' ->return (e' + f')
eval (Mul e f) =
eval e >>=\e' ->
eval f >>=\f' ->return (e' * f')
eval (Div e f) =
eval e >>=\e' ->
eval f >>=\f' ->
divSafe e' f'
which suggests the “do notation” :
eval::Expr->MaybeInt
eval (Con v) =return v
eval (Add e f) =do
e' <- eval e
f' <- eval f
return (e' + f')
eval (Mul e f) =do
e' <- eval e
f' <- eval f
return (e' * f')
eval (Div e f) =do
e' <- eval e
f' <- eval f
divSafe e' f'
For the remainder of this document we will avoid the ‘do’ notation.
The Monad class
Working file:monads2.hs
The discussion above motivates the definition of the Monad class:
instanceMonadMaybewherereturn::a->Maybeareturn=Just(>>=)::Maybea-> (a->Maybeb) ->Maybeb
ma >>= k =case ma ofNothing->NothingJust a -> k a
*Main> :l monads2.hs
[1 of 1] Compiling Main ( monads2.hs, interpreted )
Ok, one module loaded.
*Main>*Main>eval (Add (Mul (Con 2) (Con 3)) (Con 4))
Just 10
*Main>eval (Div (Con 3) (Con 0))
Nothing
IO version
Now we get an IO version for free:
evalIO::Expr->IOInt
evalIO (Con v) =return v
evalIO (Add e f) = evalIO e >>=\e' -> evalIO f >>=\f' ->return (e' + f')
evalIO (Mul e f) = evalIO e >>=\e' -> evalIO f >>=\f' ->return (e' * f')
evalIO (Div e f) = evalIO e >>=\e' -> evalIO f >>=\f' ->return (e' `div` f')
For example, we could enrich this as follows:
evalIO::Expr->IOInt
evalIO (Con v) =return v
evalIO (Add e f) =putStrLn ("adding "++show e ++" and "++show f) >>=\_ ->
evalIO e >>=\e' -> evalIO f >>=\f' ->return (e' + f')
evalIO (Mul e f) = evalIO e >>=\e' -> evalIO f >>=\f' ->return (e' * f')
Note that >>= \_ -> can be substituted with >> , so that we can write:
evalIO::Expr->IOInt
evalIO (Con v) =return v
evalIO (Add e f) =putStrLn ("adding "++show e ++" plus "++show f) >>
evalIO e >>=\e' -> evalIO f >>=\f' ->return (e' + f')
evalIO (Mul e f) =putStrLn ("multiplying "++show e ++" times "++show f) >>
evalIO e >>=\e' -> evalIO f >>=\f' ->return (e' * f')
evalIO (Div e f) =
evalIO f >>=\f' ->case f' of0->putStrLn"Oh! can not divide by zero">>return0otherwise->putStrLn ("dividing "++show e ++" by "++show f) >>
evalIO e >>=\e' ->return (e' `div` f')
*Main> :r
[1 of 1] Compiling Main ( monads2.hs, interpreted )
Ok, one module loaded.
*Main>*Main> evalIO (Add (Mul (Con 2) (Con 3)) (Con 4))
adding Mul (Con 2) (Con 3) plus Con 4
multiplying Con 2 times Con 3
10
*Main>*Main> evalIO (Div (Con 3) (Con 0))
Oh! can not divide by zero
0
*Main> evalIO $ Div (Con 6) (Con 2)
dividing Con 6 by Con 2
3
Homework: handle the Either monad
Note: need to give an argument so as to make it kind * -> *
*Main> :k Either String
Either String :: * ->*
evalEither::Expr->EitherStringInt
evalEither (Con v) =return v
evalEither (Add e f) = evalEither e >>=\e' -> evalEither f >>=\f' ->return (e' + f')
evalEither (Mul e f) = evalEither e >>=\e' -> evalEither f >>=\f' ->return (e' * f')
evalEither (Div e f) = evalEither e >>=\e' -> evalEither f >>=\f' -> divEither e' f'
Prelude> :r
[1 of 1] Compiling Main ( monads2.hs, interpreted )
Ok, one module loaded.
*Main>*Main> evalEither $ Div (Con 6) (Con 2)
Right 3
*Main> evalEither (Div (Con 3) (Con 0))
Left "Divde by zero"
typeValue=IntdataExpr=LitValue
| AddExprExpr
| MulExprExpr-- Example:-- 2 * 3 + 4-- Add (Mul (Lit 2) (Lit 3)) (Lit 4)eval::Expr-> [Value]
eval (Lit e) =return e
eval (Add e f) = eval e >>=\e' -> eval f >>=\f' ->return (e' + f')
eval (Mul e f) = eval e >>=\e' -> eval f >>=\f' ->return (e' * f')
Prelude> :l monads3.hs
[1 of 1] Compiling Main ( monads3.hs, interpreted )
Ok, one module loaded.
*Main>*Main>eval $ Add (Mul (Lit 2) (Lit 3)) (Lit 4)
[10]
Exercise: obtain all prime numbers less than or equal to n
factors::Int-> [Int]
factors x = [2..div x 2] >>=\y ->ifmod x y ==0then [y] else[]primes::Int-> [Int]
primes n = [2..n] >>=\x ->ifnull (factors x) then [x] else[]
factors::Int-> [Int]
factors x = [2..div x 2] >>= (\y -> guard (mod x y ==0) >>return y)
primes::Int-> [Int]
primes n = [2..n] >>= (\x -> guard (null (factors x)) >>return x)
Exercise: eval with square roots
typeValue=FloatdataExpr=LitValue
| AddExprExpr
| MulExprExpr
| SqrExpreval::Expr-> [Value]
eval (Lit e) =return e
eval (Add e f) = eval e >>=\e' -> eval f >>=\f' ->return (e' + f')
eval (Mul e f) = eval e >>=\e' -> eval f >>=\f' ->return (e' * f')
eval (Sqr e) = eval e >>=\e' -> [-sqrt e', sqrt e']
> :r
[1 of 1] Compiling Main ( monads3.hs, interpreted )
Ok, one module loaded.
>>eval $ Add (Lit 2) (Sqr (Lit 9))
[-1.0,5.0]
State monad
Working file:monads4.hs
Variable mutation is achieved in Haskell through function application.
f :: s -> (a,s)
a is the type of the value
s is the state
A “state transformation” is an element in the set of functions from s to s . (Thus a state stransformation can be identified with a Lambda.)
Let us start by defining the type synonim:
typeStatesa=s-> (a,s)
(The name ”State” is unfortunate. It should be called ”StateModifier”, since it is a lambda.)
Example:
f::StateIntString
f n = (show n, n)
Prelude> :l monads4.hs
[1 of 1] Compiling Main ( monads4.hs, interpreted )
Ok, one module loaded.
*Main>*Main> f 7
("7",7)
*Main>
Example:
This models the imperative commandi++ :
inc::StateIntChar
inc x = ('i', x +1)
*Main> inc 7
('i',8)
Making State s a monad.
What can be made a monad is State s with s fixed, since:
:kind State String ⟶ * -> *
To be a “certified” monad we would need to define:
instance Monad (State s) where
But to be a monad (“certified” or not), we just need to define ‘return’ and ‘bind’.
Return is easy:
-- return:ret::a->Statesa
ret a =\s -> (a,s)
To motivate ‘bind’, let us look at the:
“eval” example
typeValue=FloatdataExpr=LitValue
| AddExprExpr
| SubExprExpr
| MulExprExpr
| DivExprExpr-- we want to keep track of the maximum valueeval::Expr->StateFloatValue
eval (Lit v) =\s -> (v, if v > s then v else s)
eval (Add e f) =\s ->let
(v, s') = eval e s
(w, s'') = eval f s'
vw = v + w
in
(vw, if vw > s'' then vw else s'')
eval (Sub e f) =\s ->let
(v, s') = eval e s
(w, s'') = eval f s'
vw = v - w
in
(vw, if vw > s'' then vw else s'')
eval (Mul e f) =\s ->let
(v, s') = eval e s
(w, s'') = eval f s'
vw = v * w
in
(vw, if vw > s'' then vw else s'')
eval (Div e f) =\s ->let
(v, s') = eval e s
(w, s'') = eval f s'
vw = v / w
in
(vw, if vw > s'' then vw else s'')
*Main> :r
[1 of 1] Compiling Main ( monads4.hs, interpreted )
Ok, one module loaded.
*Main>*Main> -- Let us represent a functionwith a list of evaluations over a
*Main> -- specified domain:
*Main>*Main> map (eval $ Mul (Lit 5) (Sub (Lit 7) (Lit 3))) [15..25]
[(20.0,20.0),(20.0,20.0),(20.0,20.0),(20.0,20.0),(20.0,20.0),(20.0,20.0),(20.0,21.0),(20.0,22.0),(20.0,23.0),(20.0,24.0),(20.0,25.0)]
This motivates the definition
-- bind:bind::Statesa-> (a->Statesb) ->Statesb
bind sa k =\s -> (k .fst$ sa s) (snd$ sa s)
Another example of Sate
Working file:monads5.hs
Let us introduce a lookup table. We add the data constructor Dec Ident Value .
The commented tags are to be interpreted as follows:
Literal ⟶ We only care about the value (“literal value”)
Variable ⟶ Variable lookup
Declaration ⟶ Variable assignment (set)
Sequence ⟶ Sequence of lookups
A value of type Table represents the “current state” of assignments of values to variables (strings).
We want to implement
eval :: Expr -> Table -> (Value, Table)
which combines two needs:
Table -> Value e.g. to read the value assigned to a variable (get)
Table -> Table to modify the table, e.g. because a new binding has been made (put)
We use State for this need:
typeStatesa=s-> (a,s)
eval::Expr->StateTableValue
We begin to implement eval as follows.
eval::Expr->StateStateValue
eval (Lit v) =\t -> (v, t)
eval (Add e f) =\t ->let
(e', t') = eval e t -- [1]
(f', t'') = eval f t' -- [2]in (e' + f', t'') -- [3]
Notes:
[1] t' might defer from t e.g. because eval e t might be incorporating a declaration.
[2] We pass t' because we want to pass the latest version of the state. Note that t'' might defer from t' (same reason as above).
[3] We return the latest version of the state (the table).
Multiplication is handled exactly the same:
eval (Mul e f) =\t ->let
(e', t') = eval e t
(f', t'') = eval f t'
in (e' * f', t'')
Now, how do we implement declaration?
eval (Dec x v) =\t -> (v, (x, v) : t)
Note that we do not care if an assignment (x,v) was allready present, because we will define a lookup that will only consider the first declaration in the list (and we are disregarding memory efficiency).
And how do we implement eval of variable lookup?
One possibility is
eval (Var x) =\t ->let
v =head [ v | (x, v) <- t]
in (v, t)
but, since the lookup might fail is preferable to use the built-in lookup :
Prelude> :t lookup
lookup :: Eq a => a -> [(a, b)] -> Maybe b
Prelude>
Prelude> -- Example:
Prelude> t = [('a', 1), ('b', 2), ('c', 3), ('b', 4)]
Prelude> lookup 'b' t
Just 2
Prelude> lookup 'd' t
Nothing
So we implement lookup as follows:
eval (Var x) =\t ->caselookup x t ofNothing->error"Undefined variable"Just v -> (v,t)
How do we implement eval of a sequence? We only care of the evaluation of the last element in the sequence:
eval (Seq[]) =error"Empty sequence"
eval (Seq [e]) = eval e
eval (Seq (e:es)) =\t ->let
(_, t') = eval e t
in eval (Seq es) t'
Putting everything togehter, the declaration of eval is:
eval::Expr->StateTableValue
eval (Lit v) =\t -> (v, t)
eval (Var x) =\t ->caselookup x t ofNothing->error"Undefined variable"Just v -> (v,t)
eval (Dec x v) =\t -> (v, (x, v) : t)
eval (Seq[]) =error"Empty sequence"
eval (Seq [e]) = eval e
eval (Seq (e:es)) =\t ->let
(_, t') = eval e t
in eval (Seq es) t'
eval (Add e f) =\t ->let
(e', t') = eval e t
(f', t'') = eval f t'
in (e' + f', t'')
eval (Mul e f) =\t ->let
(e', t') = eval e t
(f', t'') = eval f t'
in (e' * f', t'')
Example:
A sequence of expressions. The first three assign x, y and z. The last one computes x + z.
With these definitions, our previous de claration of eval becomes:
eval2::Expr->State2TableValue
eval2 (Lit v) = ret v
eval2 (Var x) = get2 `bind`\t ->caselookup x t ofNothing->error"Variable not defined"Just v -> ret v
eval2 (Set x v) = get2 `bind`\t -> put2 ((x,v):t) `bind`\_ -> ret v
eval2 (Seq[]) =error"Empty sequence"
eval2 (Seq [e]) = eval2 e
eval2 (Seq (e:es)) = eval2 e `bind`\_ -> eval2 (Seq es) `bind` ret
eval2 (Add e f) = eval2 e `bind`\v -> eval2 f `bind`\w -> ret (v + w)
eval2 (Mul e f) = eval2 e `bind`\v -> eval2 f `bind`\w -> ret (v * w)
and we verify it works:
*Main> :r
[1 of 1] Compiling Main ( monads6.hs, interpreted )
Ok, one module loaded.
*Main>*Main> eval2 sq1 []
(36,[("z",29),("y",17),("x",7)])
*Main>*Main> eval2 sq2 []
(220,[("z",29),("y",17),("x",7)])
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This document elaborates on the lectures on the topic of \emph{Monads} imparted by Irfan Ali between May 27 and June 7, 2022.
\section{Motivating example}
\label{sec:org1f860bb}
\textbf{Working file:} \texttt{monads1.hs}
\vspace{1ex}
Following Philip Walder's \href{https://homepages.inf.ed.ac.uk/wadler/papers/marktoberdorf/baastad.pdf}{paper} \emph{Monads for functional programming}, we start with the implementation of the "calculator" data type \texttt{Expr} together with an "evaluation" function, \texttt{eval}, as follows:
\begin{verbatim}
data Expr = Con Int
| Add Expr Expr
| Mul Expr Expr
| Div Expr Expr
eval' :: Expr -> Int
eval' (Con v) = v
eval' (Add e f) = eval' e + eval' f
eval' (Mul e f) = eval' e * eval' f
eval' (Div e f) = eval' e `div` eval' f
\end{verbatim}
Note that both \texttt{Expr} and \texttt{eval'} are defined recursively.
\begin{verbatim}
Prelude> :l monads1.hs
[1 of 1] Compiling Main ( monads1.hs, interpreted )
Ok, one module loaded.
*Main>
*Main> -- Example:
*Main> -- 2 * 3 + 4
*Main>
*Main> eval' (Add (Mul (Con 2) (Con 3)) (Con 4))
10
'*Main> -- This throws an error:
*Main>
*Main> eval' (Div (Con 3) (Con 0))
*Exception: divide by zero
\end{verbatim}
We now want to eliminate the exception error due to division by zero, so we define \texttt{divSafe} and \texttt{evalSafe} .
\begin{verbatim}
divSafe :: Int -> Int -> Maybe Int
divSafe _ 0 = Nothing
divSafe x y = Just (x `div` y)
evalSafe :: Expr -> Maybe Int
\end{verbatim}
A naive declaration of \texttt{evalSafe} such as
\begin{verbatim}
evalSafe :: Expr -> Maybe Int
evalSafe (Con v) = v
evalSafe (Add e f) = evalSafe e + evalSafe f
evalSafe (Mul e f) = evalSafe e * evalSafe f
evalSafe (Div e f) = evalSafe e `divSafe` evalSafe f
\end{verbatim}
would not work.\\
Problem: How to feed operators +, *, etc. with numbers. (Need to extract numbers out of 'Maybe'.)\\
Now this works, but is too verbose:
\begin{verbatim}
evalSafe :: Expr -> Maybe Int
evalSafe (Con v) = Just v
evalSafe (Add e f) = case evalSafe e of
Nothing -> Nothing
Just e' -> case evalSafe f of
Nothing -> Nothing
Just f' -> Just (e' + f')
evalSafe (Mul e f) = case evalSafe e of
Nothing -> Nothing
Just e' -> case evalSafe f of
Nothing -> Nothing
Just f' -> Just (e' * f')
evalSafe (Div e f) = case evalSafe e of
Nothing -> Nothing
Just e' -> case evalSafe f of
Nothing -> Nothing
Just f' -> e' `divSafe` f'
\end{verbatim}
\begin{verbatim}
Prelude> :r
[1 of 1] Compiling Main ( monads1.hs, interpreted )
[1 of 1] Compiling Main ( monads3.hs, interpreted )
Ok, one module loaded.
>
> eval $ Add (Lit 2) (Sqr (Lit 9))
[-1.0,5.0]
\end{verbatim}
\section{State monad}
\label{sec:org644119f}
\textbf{Working file:} \texttt{monads4.hs}
\vspace{1ex}
Variable mutation is achieved in Haskell through function application.
\texttt{f :: s -> (a,s)}
\begin{itemize}
\item \texttt{a} is the type of the value
\item \texttt{s} is the state
\end{itemize}
A "state transformation" \emph{is} an element in the set of functions from \texttt{s} to \texttt{s} . (Thus a state stransformation can be identified with a \emph{Lambda}.) \\
Let us start by defining the type synonim:
\begin{verbatim}
type State s a = s -> (a,s)
\end{verbatim}
(The name "\texttt{State}" is unfortunate. It should be called "\texttt{StateModifier}", since it is a lambda.) \\
Example:
\begin{verbatim}
f :: State Int String
f n = (show n, n)
\end{verbatim}
\begin{verbatim}
Prelude> :l monads4.hs
[1 of 1] Compiling Main ( monads4.hs, interpreted )
Ok, one module loaded.
*Main>
*Main> f 7
("7",7)
*Main>
\end{verbatim}
Example: \\
This models the \emph{imperative command} \texttt{i++} :
\begin{verbatim}
inc :: State Int Char
inc x = ('i', x + 1)
\end{verbatim}
\begin{verbatim}
*Main> inc 7
('i',8)
\end{verbatim}
\subsection{Making \texttt{State s} a monad.}
\label{sec:org6e73735}
What can be made a monad is \texttt{State s} with \texttt{s} fixed, since:
\texttt{:kind State String} evaluates to \texttt{* -> *} \\
To be a "certified" monad we would need to define:
\texttt{instance Monad (State s) where} \\
But to be a monad ("certified" or not), we just need to define 'return' and 'bind'. \\
Return is easy:
\begin{verbatim}
-- return:
ret :: a -> State s a
ret a = \s -> (a,s)
\end{verbatim}
To motivate 'bind', let us look at the:
\subsubsection{"eval" example}
\label{sec:orgd7936d9}
\begin{verbatim}
type Value = Float
data Expr = Lit Value
| Add Expr Expr
| Sub Expr Expr
| Mul Expr Expr
| Div Expr Expr
-- we want to keep track of the maximum value
eval :: Expr -> State Float Value
eval (Lit v) = \s -> (v, if v > s then v else s)
eval (Add e f) = \s ->
let
(v, s') = eval e s
(w, s'') = eval f s'
vw = v + w
in
(vw, if vw > s'' then vw else s'')
eval (Sub e f) = \s ->
let
(v, s') = eval e s
(w, s'') = eval f s'
vw = v - w
in
(vw, if vw > s'' then vw else s'')
eval (Mul e f) = \s ->
let
(v, s') = eval e s
(w, s'') = eval f s'
vw = v * w
in
(vw, if vw > s'' then vw else s'')
eval (Div e f) = \s ->
let
(v, s') = eval e s
(w, s'') = eval f s'
vw = v / w
in
(vw, if vw > s'' then vw else s'')
\end{verbatim}
\begin{verbatim}
*Main> :r
[1 of 1] Compiling Main ( monads4.hs, interpreted )
Ok, one module loaded.
*Main>
*Main> -- Let us represent a function with a list of evaluations over a
\item \texttt{Sequence} \hspace{1em}:\hspace{1em} Sequence of lookups
\end{itemize}
A value of type \texttt{Table} represents the "current state" of assignments of \emph{values} to \emph{variables} (strings). \\
We want to implement
\texttt{eval :: Expr -> Table -> (Value, Table)}
which combines two needs:
\begin{itemize}
\item \texttt{Table -> Value} e.g. to read the value assigned to a variable (get)
\item \texttt{Table -> Table} to modify the table, e.g. because a new binding has been made (put)
\end{itemize}
We use \texttt{State} for this need:
\begin{verbatim}
type State s a = s -> (a,s)
eval :: Expr -> State Table Value
\end{verbatim}
We begin to implement \texttt{eval} as follows.
\begin{verbatim}
eval :: Expr -> State State Value
eval (Lit v) = \t -> (v, t)
eval (Add e f) = \t ->
let
(e', t') = eval e t -- [1]
(f', t'') = eval f t' -- [2]
in (e' + f', t'') -- [3]
\end{verbatim}
Notes:
\begin{itemize}
\item\relax [1] \texttt{t'} might defer from \texttt{t} e.g. because \texttt{eval e t} might be incorporating a declaration.
\item\relax [2] We pass \texttt{t'} because we want to pass the latest version of the state. Note that \texttt{t''} might defer from \texttt{t'} (same reason as above).
\item\relax [3] We return the latest version of the state (the table).
\end{itemize}
Multiplication is handled exactly the same:
\begin{verbatim}
eval (Mul e f) = \t ->
let
(e', t') = eval e t
(f', t'') = eval f t'
in (e' * f', t'')
\end{verbatim}
Now, how do we implement \emph{declaration}?
\begin{verbatim}
eval (Dec x v) = \t -> (v, (x, v) : t)
\end{verbatim}
Note that we do not care if an assignment \texttt{(x,v)} was allready present, because we will define a \texttt{lookup} that will only consider the first declaration in the list (and we are disregarding memory efficiency).
And how do we implement \texttt{eval} of variable lookup?
One possibility is
\begin{verbatim}
eval (Var x) = \t ->
let
v = head [ v | (x, v) <- t]
in (v, t)
\end{verbatim}
but, since the lookup might fail is preferable to use the built-in \texttt{lookup} :