関数の実装の方法
考え方のコツ
以下の2つを分離して考えると良い
inputからASTを作る
ASTを評価する
普通に考えるとそらそうか、という感じmrsekut.icon
parseとevalを同時に作ろうとして混乱した
関数定義のASTを定義する
Lambda String ASTを作る
https://gyazo.com/cec833a9adecf8fed85b70def1518459
変数に束縛するときはAssign String Expを使う
https://gyazo.com/051abe87c469240edd88a7aff9440202
関数呼び出しのASTを定義する
Call String Exp
https://gyazo.com/0fe19d6ec6de00c089ce30f530461a8f
環境を表すEnvironmentオブジェクトを作成している ref code:nim
# 環境を表す型
Environment* = ref object of RootObj
outer: Environment
新たにスコープに入るタイミングで、元のEnvのインスタンスをouterプロパティに含めた、新たなEnvインスタンスを作成する ref まず今の環境の中を探す
なかったらさらに外の環境の中を探す
というのを繰り返す
最後までなかったらエラー。
Haskellで関数を実装することの勉強にもなる
「関数を実装する」ってコンパイラ的な意味の。
ExpとValue
一部省略してる
code:hs
data Exp = Abs Name Exp -- λ式
| App Exp Exp -- 関数適用
data Value = IntVal Integer -- 整数
| FuncVal Env Name Exp -- 関数
deriving (Show)
Abs Name Exp
Nameは関数名、Expは関数のbodyかな
App Exp Exp
1つ目のExpはFuncValなはず
そうでなければeval0ではエラー
2つ目のExpは引数
つまりすべての関数は一つのみの引数をとる ?
Env
code:hs
type Env = Map.Map Name Value
MapはHaskellの辞書みたいなやつ
関数呼び出しのテストのための方法
改行をサポートして、テストケースに関数定義と呼び出しを複数行で書く
code:hs
-- こんな書き方ができるのか知らんが
shouleBe """f x = x + 1
f 2"""
3
セミコロンをサポートして、テストケースに関数定義と呼び出しを1行で書く
shouldBe "f x = x + 1; f 2" 3
ASTでEnvと、呼び出しを書く
shouldBe1 (<Env>) "f x" 3
入力の文字列を配列として渡し、最終行の結果と比較する
shouldBe2 ["f x = x + 1","f 2"] 3
これを実装したmrsekut.icon