Readerモナドを試してみる

30分プログラム、その663。Readerモナドを試してみました。
The Reader monadを読んでたら、環境がどうのこうの書いてあったので、簡単なプログラミング言語を作ってみました。環境が使いたかっただけなので、変数束縛と変数参照のほかには、整数リテラルと加算演算子ぐらいしかありません。

前に読んだHaskellの入門書には「複数の関数で引数を共有したいときはReaderモナドを使うといいよー」と書いてあったけど、微妙に違う気がする。共有できるのは引数一個だけだし、共有してる変数を書き換えることもできるし。

使い方

*Main> runEval $ Int 40 `Add` Int 2
42

*Main> runEval $ Let ("x",Int 1) $ Int 4 `Add` Var "x"
5

ソースコード

import Control.Monad.Reader

data Expr = Let (String,Expr) Expr
          | Var String
          | Int Int
          | Expr `Add` Expr deriving Show

type Env  = [(String,Int)]

eval :: Expr -> Reader Env Int
eval (Int n)       =
    return n
eval (Add lhs rhs) =
    do x <- eval lhs
       y <- eval rhs
       return $ x + y
eval (Var name) =
    do val <- asks $ lookup name
       return $ case val of
                  Just x  -> x
                  Nothing -> 0
eval (Let (name,value) body) =
    do value' <- eval value
       local ((name,value'):) $ eval body

runEval e = runReader (eval e) []