Skip to content

Instantly share code, notes, and snippets.

@jerrypnz
Last active August 29, 2015 14:20
Show Gist options
  • Save jerrypnz/82828f6bc3ee40428e12 to your computer and use it in GitHub Desktop.
Save jerrypnz/82828f6bc3ee40428e12 to your computer and use it in GitHub Desktop.
Expr Evaluator with Read
--- Using a monad to implement the evaluation example but this time using "do"
import Control.Applicative
import Control.Monad
data Expr = C Float |
Expr :+ Expr|
V String |
Let String Expr Expr |
Read
deriving Show
type Env = [(String, Float)]
type Stream = [Float]
--- Yes, this could be done using the pre-defined State monad...but this is more useful for learning from....
newtype Compute a = Comp{ compExpr :: Stream -> Env -> (Stream, Env, a)}
instance Monad Compute where
return x = Comp (\stream env -> (stream, env , x))
e >>= f = Comp(\stream env -> let (stream', env', v) = compExpr e stream env in compExpr (f v) stream' env')
instance Functor Compute where
fmap = liftM
instance Applicative Compute where
pure = return
(<*>) = ap
eval :: Expr -> Compute Float
eval (C x) = return x
eval (e1 :+ e2) = do
v1 <- eval e1
v2 <- eval e2
return (v1 + v2)
eval (V v) = find' v
eval Read = Comp(\(x:xs) env -> (xs, env, x))
eval (Let v e1 e2) = do
v1 <- eval e1
extend' v v1
v2 <- eval e2
return v2
---Find a variable's value by looking in the environment
find :: String -> Env -> Float
find v [] = error ("Unbound variable: " ++ v)
find v1 ((v2,e):es) = if v1 == v2 then e else find v1 es
---Use find properly
---find' :: String -> Env -> (Env, Float)
---find' v env = (env, find v env)
find' :: String -> Compute Float
find' v = Comp(\s env-> (s, env, find v env))
---We extend with variables that may already appear in
---the environment so as to have a sensible block
---structure, so, for example,
---evaluate (Let “x” (C 5) (Let “x” (C 4) (V “x”))
---gives 4.0 and not 5.0
extend :: String -> Float -> Env -> Env
extend v e env = (v,e):env
---Use extend properly
---extend' :: String -> Float -> Env -> (Env, Float)
---extend' v e env = (extend v e env, e)
extend' :: String -> Float -> Compute Float
extend' v e = Comp(\s env -> (s, extend v e env, e))
---Finally answer to start the computation with an empty environment, and returns final answer
---answer :: Expr -> Float
answer e s = (compExpr (eval e) s [])
e0 = Let "x" (C 2.0) (V "x" :+ C 3.0)
e1 = Let "x" (C 2.0) (Let "y" (C 3.0) (V "x" :+ V "y"))
e2 = Let "x" (C 2.0) (Let "y" (C 3.0) (V "x" :+ V "x"))
e3 = Read :+ Read
e4 = Let "x" (C 2.0) (Let "y" (C 3.0) (V "x" :+ V "y" :+ Read))
-- λ> answer e3 [1.1, 2.0]
-- ([],[],3.1)
-- λ> answer e3 [1.1, 5.1, 2.0]
-- ([2.0],[],6.2)
-- λ> answer e4 [1.1, 5.1, 2.0]
-- ([5.1,2.0],[("y",3.0),("x",2.0)],6.1)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment