Haskellでevalを作る
evalは最初からIdentityモナドで実装しておくと後々楽になる
以下のようなものを使うのが一般的な実装
結果を出力する際にIO
envを持ち回る際にReader
エラーメッセージにExcept
モナド変換子のtutorial
記事の流れがめちゃくちゃいいmrsekut.icon
step by stepより簡潔
モナド変換子がない世界ではどうしていたかを示し、その辛さを共有
その後、モナド変換子を使ったものを示す
eval関数を「最初からモナドを使う」という想定で実装する
何のモナドを使うかは決めていないが、とりあえず使うことは使うという
なにもないならとりあえずIdentityモナドを使って書いておく
「モナドなし実装」と「モナドあり実装」は結構差があるが、
「Aモナドあり実装」と「Bモナドあり実装」はほぼ変わらない
「Aモナドあり実装」のあとに「Bモナドもほしい」となればモナド変換子で組み合わせる
まず最初に逐次的に書いて、モナド変換子を使ったものに書き換えていく
関数定義と関数適用の実装あり
変数定義はない
逐次的に加算や関数を扱えるインタプリタを実装する
ErrorTを導入する
throwErrorとかする
正しくない式に対してエラーメッセージを表示する
code:hs
runEval2 :: Eval2 a -> Either String a
runEval3 :: Env -> Eval2 a -> Either String a
Envをグローバル定数として持っている感じ
monkey-nimの時みたいにEnvが入れ子にならない
評価のステップ数をカウントするプロファイリング機能を付け加えるために
なので、状態はInteger
ここまでは前段階のモナドを包んでいたが、ここでは包まれる側
ここの上限関係の意味は何?
評価中に遭遇した変数名を記録するために
IOモナドを導入する
IOモナド変換子は定義できないので代わりにIdentityを使っていた所をIOにする
デバッグとかに使える