今回は電卓プログラムに「遅延評価 (delayed evaluation または lazy evaluation)」という機能を追加してみましょう。まず最初に、遅延評価について簡単に説明します。
一般的なプログラミング言語の場合、関数を呼び出す前に引数の式が評価され、その結果が関数に渡されます。これを「正格 (strict) な評価」といいます。これに対し、実際に値が必要となる時まで式の評価を行わない方法を「遅延評価」といいます。
プログラミング言語では、関数型言語の Haskell が遅延評価を行います。また、Scheme には遅延評価を行うための機能 (delay, force) が用意されています。今回は Scheme と同様に、delay と force を電卓プログラムに追加することにします。
次は、delay と force の動作を説明します。
delay(式) force(promise)
電卓プログラムの場合、遅延評価を実現するため構文に delay 式を追加します。delay 式は引数の式を評価しないで「プロミス (Promise)」というデータを返します。
引数の式はこのプロミスに保存されていて、組み込み関数 force(promise) を実行すると、プロミスに格納されている式を評価してその値を返します。このとき、値がプロミスに保存されることに注意してください。再度 force(pomise) を実行すると、保存された値が返されます。
簡単な使用例を示しましょう。
Calc> a = delay(begin println("oops!"), 1 + 2 end); <Promise> Calc> force(a); oops! 3 Calc> force(a); 3
delay(begin ... end) の返り値を変数 a にセットします。このとき、引数の begin 式は評価されません。force(a) を実行すると、 式 begin println("oops!"), 1 + 2 end が評価されるので、画面に oops! が表示されて返り値は 3 になります。
次に、force(a) を実行すると、式を評価せずに保存した値を返すので oops! は表示されません。
それではプログラムを作りましょう。字句解析はトークンに DELAY を、キーワード keyTable に delay と DELAY を追加するだけです。delay 式の処理は関数 factor で行います。次のリストを見てください。
リスト : 因子の処理 func factor(lex *Lex) Expr { switch lex.Token { ・・・省略・・・ case DELAY: lex.getToken() if lex.Token != '(' { panic(fmt.Errorf("delay: '(' expected")) } lex.getToken() e := expression(lex) if lex.Token != ')' { panic(fmt.Errorf("delay: ')' expected")) } lex.getToken() return newMakePromise(e) ・・・省略・・・ } }
トークンが DELAY の場合、次のトークンが左カッコ '(' であることを確認してから、expression で式を読み込みます。そして、次のトークンが右カッコであることを確認してから、関数 newMakePromise で式 e を格納した構造体 MakePromise を生成して返します。あとは、MakePromise を Eval で評価すると、プロミスを表す構造体 Promise を生成するようにします。
次はプロミスを表す構造体 Promise を定義します。
リスト : プロミスの定義 type Promise struct { val Value expr Expr env *Env } func newPromise(expr Expr, env *Env) *Promise { return &Promise{nil, expr, env} } func (_ *Promise) isTrue() bool { return true } func (_ *Promise) String() string { return "<Promise>" } // Promise の生成 type MakePromise struct { expr Expr } func newMakePromise(expr Expr) *MakePromise { return &MakePromise{expr} } func (p *MakePromise) Eval(env *Env) Value { return newPromise(p.expr, env) }
構造体 Promise のフィールド変数 val は式を評価した結果を格納します。expr が評価する式です。env は Promise を生成したときの環境です。プロミスを評価するときは、それを生成したときの環境で行います。プロミスを評価するときの環境では行わないことに注意してください。Promise は値なので、メソッド isTrue を定義します。また、Promise を表示するため、メソッド String() も定義します。
構造体 MakePromise は式 expr を格納するだけです。メソッド Eval は MakePromise に格納されている式 p.expr と環境 env を関数 newPromise に渡して Promise を生成するだけです。
最後にプロミスを評価する組み込み関数 force を作ります。
リスト : プロミスの評価 func force(v Value) Value { p, ok := v.(*Promise) if !ok { panic(fmt.Errorf("force: Promise required, %v", v)) } if p.val == nil { p.val = p.expr.Eval(p.env) } return p.val }
force は簡単です。最初に引数 v がプロミスであることを確認します。そして、p.val が nil ならば、まだ式を評価していないので、格納してある環境 p.env で式 p.expr をメソッド Eval で評価します。最後に p.val を返します。
それでは、遅延評価の簡単な例題として「たらいまわし関数」を取り上げます。次のリストを見てください。
リスト : たらいまわし関数 def tak(x, y, z) if x <= y then z else tak(tak(x - 1, y, z), tak(y - 1, z, x), tak(z - 1, x, y)) end end def tarai(x, y, z) if x <= y then y else tarai(tarai(x - 1, y, z), tarai(y - 1, z, x), tarai(z - 1, x, y)) end end
関数 tarai や tak は「たらいまわし関数」といって、再帰的に定義されています。これらの関数は、引数の与え方によっては実行に時間がかかるため、Lisp などのベンチマークに利用されることがあります。
関数 tarai は通称「竹内関数」と呼ばれていて、日本の代表的な Lisper である竹内郁雄先生によって考案されたそうです。そして、関数 tak は関数 tarai のバリエーションで、John Macarthy 先生によって作成されたそうです。たらいまわし関数が Lisp のベンチマークで使われていたことは知っていましたが、このような由緒ある関数だとは思ってもいませんでした。
関数 tarai は遅延評価を行う処理系では高速に実行できることが知られています。tarai のプログラムを見てください。x <= y のときに y を返しますが、このとき引数 z の値は必要ありませんね。引数 z の値は x > y のときに計算するようにすれば、無駄な計算を省略することができます。なお、関数 tak は x <= y のときに z を返しているため、遅延評価で高速化することはできません。ご注意ください。
delay と force を使うと、たらいまわし関数は次のようになります。
リスト : delay と force による遅延評価 def taraiDelay(x, y, z) if x <= y then y else let zz = force(z) in taraiDelay(taraiDelay(x - 1, y, delay(zz)), taraiDelay(y - 1, zz, delay(x)), delay(taraiDelay(zz - 1, x, delay(y)))) end end end
遅延評価したい処理をプロミスにして引数 z に渡します。そして、x > y のときに引数 z のプロミスを force で評価します。すると、プロミス内の処理が評価されて z の値を求めることができます。たとえば、delay(0) を z に渡す場合、force(z) とすると返り値は 0 になります。delay(x) を渡せば、x に格納されている値が返されます。delay(taraiDelay(...)) を渡せば taraiDelay が実行されて、その値を求めることができます。
それでは、実際に実行してみましょう。
Calc> let s = clock() in println(tarai(12,6,0)), since(s) end; 12 4.077236115s Calc> let s = clock() in println(taraiDelay(12,6,delay(0))), since(s) end; 12 222.4µs 実行環境: Julia 1.23.2, Ubunts 22.04 (WSL2), Intel Core i5-6200U 2.30GHz
tarai の場合、遅延評価の効果はとても大きいですね。
ところで、delay と force がなくても、クロージャを使って遅延評価を行うことができます。次のリストを見てください。
リスト : クロージャによる遅延評価 def taraiClo(x, y, z) if x <= y then y else let zz = z() in taraiClo(taraiClo(x - 1, y, fn() zz end), taraiClo(y - 1, zz, fn() x end), fn() taraiClo(zz - 1, x, fn() y end) end) end end end
遅延評価したい処理をクロージャに包んで引数 z に渡します。そして、x > y のときに引数 z の関数を呼び出します。すると、クロージャ内の処理が評価されて z の値を求めることができます。たとえば、fn() 0 end を z に渡す場合、z() とすると返り値は 0 になります。fn() x end を渡せば、x に格納されている値が返されます。fn() taraiClo(...) end を渡せば、関数 taraiClo が実行されてその値が返されるわけです。
それでは、実際に実行してみましょう。Calc> let s = clock() in println(taraiDelay(500,250,delay(0))), since(s) end; 500 88.671687ms Calc> let s = clock() in println(taraiClo(500,250,fn() 0 end)), since(s) end; 500 89.123656ms
電卓プログラムの場合、遅延評価とクロージャで実行速度に大きな差はありませんでした。ただし、クロージャの場合は式の評価結果をキャッシュしていないことに注意してください。たとえば、a = delay(tarai(12,6,0)) と b = fn() tarai(12,6,0) end とした場合、forc(a) を何度評価しても tarai の評価は一度きりですが、クロージャ b() を複数回評価すると、何度も tarai を評価してしまいます。
今回はここまでです。次回は遅延評価の簡単な応用例として、「遅延ストリーム」を実装してみましょう。
// // calc9.go : 電卓プログラム (遅延評価を追加) // // Copyright (C) 2014-2021 Makoto Hiroi // package main import ( "fmt" "os" "math" "time" "text/scanner" ) // キーワード const ( DEF = -(iota+10) END IF THEN ELSE NOT AND OR EQ NE LT GT LE GE BGN WHL DO LET IN FN CALL LIST DELAY ) // キーワード表 var keyTable = make(map[string]rune) func initKeyTable() { keyTable["def"] = DEF keyTable["end"] = END keyTable["if"] = IF keyTable["then"] = THEN keyTable["else"] = ELSE keyTable["and"] = AND keyTable["or"] = OR keyTable["not"] = NOT keyTable["begin"] = BGN keyTable["while"] = WHL keyTable["do"] = DO keyTable["let"] = LET keyTable["in"] = IN keyTable["fn"] = FN keyTable["call"] = CALL keyTable["list"] = LIST keyTable["delay"] = DELAY } // 値 type Value interface { isTrue() bool } // 変数 type Variable string // 局所変数の環境 type Env struct { name Variable val Value next *Env } // 構文木 type Expr interface { Eval(*Env) Value } // 数 type Num interface { Value Expr neg() Value sign() int add(Value) Value sub(Value) Value mul(Value) Value div(Value) Value } // 比較 type Cmp interface { compare(Value) int } // // 数値 // type Int int64 type Flt float64 // エラー func errorNum(mes string, v Value) error { return fmt.Errorf("%sNumber required, %v", mes, v) } func errorInt(mes string, v Value) error { return fmt.Errorf("%sInteger required, %v", mes, v) } // Value の実装 func (n Int) isTrue() bool { return n != 0 } func (n Flt) isTrue() bool { return n != 0.0 } // Expr の実装 func (e Int) Eval(_ *Env) Value { return e } func (e Flt) Eval(_ *Env) Value { return e } // 符号の反転 func (n Int) neg() Value { return -n } func (n Flt) neg() Value { return -n } // 符号を求める func (n Int) sign() int { switch { case n > 0: return 1 case n < 0: return -1 default: return 0 } } func (n Flt) sign() int { switch { case n > 0.0: return 1 case n < 0.0: return -1 default: return 0 } } // 四則演算 func (n Int) add(x Value) Value { switch m := x.(type) { case Int: return n + m case Flt: return Flt(n) + m } panic(errorNum("+, ", x)) } func (n Flt) add(x Value) Value { switch m := x.(type) { case Int: return n + Flt(m) case Flt: return n + m } panic(errorNum("+, ", x)) } func (n Int) sub(x Value) Value { switch m := x.(type) { case Int: return n - m case Flt: return Flt(n) - m } panic(errorNum("-, ", x)) } func (n Flt) sub(x Value) Value { switch m := x.(type) { case Int: return n - Flt(m) case Flt: return n - m } panic(errorNum("-, ", x)) } func (n Int) mul(x Value) Value { switch m := x.(type) { case Int: return n * m case Flt: return Flt(n) * m } panic(errorNum("*, ", x)) } func (n Flt) mul(x Value) Value { switch m := x.(type) { case Int: return n * Flt(m) case Flt: return n * m } panic(errorNum("*, ", x)) } func (n Int) div(x Value) Value { switch m := x.(type) { case Int: return n / m case Flt: return Flt(n) / m } panic(errorNum("/, ", x)) } func (n Flt) div(x Value) Value { switch m := x.(type) { case Int: return n / Flt(m) case Flt: return n / m } panic(errorNum("/, ", x)) } // Cmp の実装 func (n Int) compare(x Value) int { switch m := x.(type) { case Int: return (n - m).sign() case Flt: return (Flt(n) - m).sign() } panic(errorNum("compare, ", x)) } func (n Flt) compare(x Value) int { switch m := x.(type) { case Int: return (n - Flt(m)).sign() case Flt: return (n - m).sign() } panic(errorNum("compare, ", x)) } // // 文字列 // type Str string // エラー func errorStr(mes string, v Value) error { return fmt.Errorf("%sString required, %v", mes, v) } // Value, Expr, Cmp の実装 func (_ Str) isTrue() bool { return true } func (s Str) Eval(_ *Env) Value { return s } func (n Str) compare(x Value) int { m, ok := x.(Str) if !ok { panic(errorStr("compare, ", x)) } switch { case n > m: return 1 case n < m: return -1 default: return 0 } } // // 配列 // type Vec []Value // エラー func errorVec(mes string, v Value) error { return fmt.Errorf("%sVector required , %v", mes, v) } // Value の実装 func (_ Vec) isTrue() bool { return true } // ベクタ生成用構文木 type Crv struct { xs []Expr } func newCrv(xs []Expr) *Crv { return &Crv{xs} } // ベクタの生成 func (a *Crv) Eval(env *Env) Value { v := make(Vec, len(a.xs)) for i := 0; i < len(a.xs); i++ { v[i] = a.xs[i].Eval(env) } return v } // ベクタの参照 type Ref struct { name Variable idxs []Expr } func newRef(name Variable, idxs []Expr) *Ref { return &Ref{name, idxs} } // アクセス位置を求める func getPos(a *Ref, env *Env) *Value { v := a.name.Eval(env) for k := 0; ; k++ { xs, ok := v.(Vec) if !ok { panic(errorVec("", v)) } y := a.idxs[k].Eval(env) i := toInt(y) if j := int(i); j < 0 || j >= len(xs) { panic(fmt.Errorf("Out of Range, %v, %v", xs, j)) } else if k == len(a.idxs) - 1 { return &xs[j] } else { v = xs[j] } } } // 評価 func (a *Ref) Eval(env *Env) Value { return *getPos(a, env) } // ベクタの更新 type Udt struct { ref *Ref val Expr } func newUdt(ref *Ref, val Expr) *Udt { return &Udt{ref, val} } // 評価 func (a *Udt) Eval(env *Env) Value { x := getPos(a.ref, env) v := a.val.Eval(env) *x = v return v } // // 連結リスト // type Cell struct { car, cdr Value } func newCell(a, b Value) *Cell { return &Cell{a, b} } // 空リスト var NIL *Cell // NIL の初期化 func makeNIL() { NIL = newCell(nil, nil) NIL.car = NIL NIL.cdr = NIL globalEnv["nil"] = NIL } // Value の実装 func (x *Cell) isTrue() bool { return x != NIL } // リストの生成 type List struct { xs []Expr } func newList(xs []Expr) *List { return &List{xs} } func (x *List) Eval(env *Env) Value { cp := NIL for i := len(x.xs) - 1; i >= 0; i-- { cp = newCell(x.xs[i].Eval(env), cp) } return cp } // リスト -> 文字列 func sprintlist(cp *Cell) string { s := "(" for cp != NIL { s += sprintValue(cp.car) b, ok := cp.cdr.(*Cell) if ok { cp = b if cp != NIL { s += " " } } else { s += " . " + sprintValue(cp.cdr) break } } s += ")" return s } // Vec -> string func sprintvec(xs Vec) string { s := "[" i := 0 for ; i < len(xs) - 1; i++ { s += sprintValue(xs[i]) + ", " } s += sprintValue(xs[i]) + "]" return s } // Value -> string func sprintValue(v Value) string { switch x := v.(type) { case *Cell: return sprintlist(x) case Vec: return sprintvec(x) default: return fmt.Sprint(x) } } // // 変数と環境 // // 環境の生成 func newEnv(name Variable, val Value, env *Env) *Env { return &Env{name, val, env} } func makeBinding(xs []Variable, es []Expr, env *Env) *Env { var env1 *Env for i := 0; i < len(xs); i++ { env1 = newEnv(xs[i], es[i].Eval(env), env1) } return env1 } // 局所変数を環境に追加 func addBinding(xs []Variable, es []Expr, env *Env) *Env { for i := 0; i < len(xs); i++ { env = newEnv(xs[i], es[i].Eval(env), env) } return env } // クロージャ用 func addBindingClo(xs []Variable, es []Expr, env, clo *Env) *Env { for i := 0; i < len(xs); i++ { clo = newEnv(xs[i], es[i].Eval(env), clo) } return clo } // 局所変数の探索 func lookup(name Variable, env *Env) (Value, bool) { for ; env != nil; env = env.next { if name == env.name { return env.val, true } } return Int(0), false } // 局所変数の更新 func update(name Variable, val Value, env *Env) bool { for ; env != nil; env = env.next { if name == env.name { env.val = val return true } } return false } // 大域的な環境 var globalEnv = make(map[Variable]Value) // 変数の評価 func (v Variable) Eval(env *Env) Value { // 局所変数の探索 val, ok := lookup(v, env) if ok { return val } // 大域変数の探索 val, ok = globalEnv[v] if !ok { panic(fmt.Errorf("unbound variable, %v", v)) } return val } // // 単項演算子 // type Op1 struct { code rune expr Expr } func newOp1(code rune, e Expr) Expr { return &Op1{code, e} } // bool を Value に変換する func boolToValue(x bool) Value { if x { return Int(1) } else { return Int(0) } } // 型変換とチェック func toNum(v Value) Num { n, ok := v.(Num) if !ok { panic(errorNum("", v)) } return n } // 評価 func (e *Op1) Eval(env *Env) Value { v := e.expr.Eval(env) switch e.code { case '-': return toNum(v).neg() case '+': return v case NOT: return boolToValue(!v.isTrue()) default: panic(fmt.Errorf("invalid Op1 code")) } } // // 二項演算子 // type Op2 struct { code rune left, right Expr } func newOp2(code rune, left, right Expr) Expr { return &Op2{code, left, right} } // 型変換とチェック func toInt(v Value) Int { n, ok := v.(Int) if !ok { errorInt("", v) } return n } func toCmp(v Value) Cmp { n, ok := v.(Cmp) if !ok { panic(fmt.Errorf("%v is uncomparable type", v)) } return n } // 評価 func (e *Op2) Eval(env *Env) Value { x := e.left.Eval(env) y := e.right.Eval(env) switch e.code { case '+': return toNum(x).add(y) case '-': return toNum(x).sub(y) case '*': return toNum(x).mul(y) case '/': return toNum(x).div(y) case '%': return toInt(x) % toInt(y) case EQ: return boolToValue(toCmp(x).compare(y) == 0) case NE: return boolToValue(toCmp(x).compare(y) != 0) case LT: return boolToValue(toCmp(x).compare(y) < 0) case GT: return boolToValue(toCmp(x).compare(y) > 0) case LE: return boolToValue(toCmp(x).compare(y) <= 0) case GE: return boolToValue(toCmp(x).compare(y) >= 0) default: panic(fmt.Errorf("invalid Op2 code")) } } // // 短絡演算子 // type Ops struct { code rune left, right Expr } func newOps(code rune, left, right Expr) Expr { return &Ops{code, left, right} } // 評価 func (e *Ops) Eval(env *Env) Value { x := e.left.Eval(env) switch e.code { case AND: if x.isTrue() { return e.right.Eval(env) } return x case OR: if x.isTrue() { return x } return e.right.Eval(env) default: panic(fmt.Errorf("invalid Ops code")) } } // // if // type Sel struct { testForm, thenForm, elseForm Expr } func newSel(testForm, thenForm, elseForm Expr) *Sel { return &Sel{testForm, thenForm, elseForm} } func (e *Sel) Eval(env *Env) Value { if e.testForm.Eval(env).isTrue() { return e.thenForm.Eval(env) } return e.elseForm.Eval(env) } // // while // type Whl struct { testForm, body Expr } func newWhl(testForm, body Expr) *Whl { return &Whl{testForm, body} } func (e *Whl) Eval(env *Env) Value { for e.testForm.Eval(env).isTrue() { e.body.Eval(env) } return Int(0) } // // begin // type Bgn struct { body []Expr } func newBgn(xs []Expr) *Bgn { return &Bgn{xs} } func (e *Bgn) Eval(env *Env) Value { var r Value for _, expr := range e.body { r = expr.Eval(env) } return r } // // let // type Let struct { vars []Variable vals []Expr body Expr } func newLet(vars []Variable, vals []Expr, body Expr) *Let { return &Let{vars, vals, body} } func (e *Let) Eval(env *Env) Value { return e.body.Eval(addBinding(e.vars, e.vals, env)) } // // 代入演算子 // type Agn struct { name Variable expr Expr } func newAgn(v Variable, e Expr) *Agn { return &Agn{v, e} } func (a *Agn) Eval(env *Env) Value { val := a.expr.Eval(env) if !update(a.name, val, env) { globalEnv[a.name] = val } return val } // // 関数 // // // 関数 // type Func interface { Value Expr Argc() int } type Func1 func(float64) float64 func (f Func1) Argc() int { return 1 } func (f Func1) isTrue() bool { return true } func (f Func1) Eval(_ *Env) Value { return f } func (f Func1) String() string { return "<Function1>" } type Func2 func(float64, float64) float64 func (f Func2) Argc() int { return 2 } func (f Func2) isTrue() bool { return true } func (f Func2) Eval(_ *Env) Value { return f } func (f Func2) String() string { return "<Function2>" } type FuncV0 func() Value func (f FuncV0) Argc() int { return 0 } func (f FuncV0) isTrue() bool { return true } func (f FuncV0) Eval(_ *Env) Value { return f } func (f FuncV0) String() string { return "<FunctionV1>" } type FuncV1 func(Value) Value func (f FuncV1) Argc() int { return 1 } func (f FuncV1) isTrue() bool { return true } func (f FuncV1) Eval(_ *Env) Value { return f } func (f FuncV1) String() string { return "<FunctionV1>" } type FuncV2 func(Value, Value) Value func (f FuncV2) Argc() int { return 2 } func (f FuncV2) isTrue() bool { return true } func (f FuncV2) Eval(_ *Env) Value { return f } func (f FuncV2) String() string { return "<FunctionV2>" } // ユーザ定義関数 type FuncU struct { name string xs []Variable body Expr } func newFuncU(name string, xs []Variable, body Expr) *FuncU { return &FuncU{name, xs, body} } func (f *FuncU) Argc() int { return len(f.xs) } func (f *FuncU) isTrue() bool { return true } func (f *FuncU) Eval(_ *Env) Value { return f } func (f *FuncU) String() string { return fmt.Sprintf("<%s>", f.name) } // クロージャ type Clo struct { xs []Variable body Expr } func newClo(xs []Variable, body Expr) *Clo { return &Clo{xs, body} } type FuncC struct { xs []Variable body Expr env *Env } func (f *FuncC) Argc() int { return len(f.xs) } func (_ *FuncC) isTrue() bool { return true } func (f *FuncC) Eval(_ *Env) Value { return f } func (_ *FuncC) String() string { return "<Closure>" } func (a *Clo) Eval(env *Env) Value { return &FuncC{a.xs, a.body, env} } // // 関数呼び出し // type App struct { fn Func xs []Expr } func newApp(fn Func, xs []Expr) *App { return &App{fn, xs} } type AppV struct { fn Expr xs []Expr } func newAppV(fn Expr, xs []Expr) *AppV { return &AppV{fn, xs} } func valueToFloat(v Value) float64 { switch x := v.(type) { case Int: return float64(x) case Flt: return float64(x) default: panic(errorNum("", v)) } } // 評価 func appFunc(fn Func, xs []Expr, env *Env) Value { switch f := fn.(type) { case Func1: x := valueToFloat(xs[0].Eval(env)) return Flt(f(x)) case Func2: x := valueToFloat(xs[0].Eval(env)) y := valueToFloat(xs[1].Eval(env)) return Flt(f(x, y)) case FuncV0: return f() case FuncV1: return f(xs[0].Eval(env)) case FuncV2: return f(xs[0].Eval(env), xs[1].Eval(env)) case *FuncU: return f.body.Eval(makeBinding(f.xs, xs, env)) case *FuncC: return f.body.Eval(addBindingClo(f.xs, xs, env, f.env)) default: panic(fmt.Errorf("%v is not function", f)) } } func (a *App) Eval(env *Env) Value { return appFunc(a.fn, a.xs, env) } func (a *AppV) Eval(env *Env) Value { v := a.fn.Eval(env) fn, ok := v.(Func) if !ok { panic(fmt.Errorf("%v is not function", v)) } if fn.Argc() != len(a.xs) { panic(fmt.Errorf("wrong number of arguments")) } return appFunc(fn, a.xs, env) } // // 遅延評価 // type Promise struct { val Value expr Expr env *Env } func newPromise(expr Expr, env *Env) *Promise { return &Promise{nil, expr, env} } func (_ *Promise) isTrue() bool { return true } func (_ *Promise) String() string { return "<Promise>" } // Promise の生成 type MakePromise struct { expr Expr } func newMakePromise(expr Expr) *MakePromise { return &MakePromise{expr} } func (p *MakePromise) Eval(env *Env) Value { return newPromise(p.expr, env) } // 評価 func force(v Value) Value { p, ok := v.(*Promise) if !ok { panic(fmt.Errorf("force: Promise required, %v", v)) } if p.val == nil { p.val = p.expr.Eval(p.env) } return p.val } // // 組み込み関数の初期化 // var funcTable = make(map[string]Func) // 値の表示 func print(x Value) Value { fmt.Print(sprintValue(x)) return x } func println(x Value) Value { fmt.Println(sprintValue(x)) return x } // ベクタの生成 func makeVector(n, x Value) Value { k := toInt(n) xs := make(Vec, int(k)) for i := 0; i < int(k); i++ { xs[i] = x } return xs } func length(v Value) Value { xs, ok := v.(Vec) if !ok { panic(errorVec("len, ", v)) } return Int(len(xs)) } func isInt(v Value) Value { _, ok := v.(Int) return boolToValue(ok) } func isFlt(v Value) Value { _, ok := v.(Flt) return boolToValue(ok) } func isVec(v Value) Value { _, ok := v.(Vec) return boolToValue(ok) } func isStr(v Value) Value { _, ok := v.(Str) return boolToValue(ok) } func isFunc(v Value) Value { _, ok := v.(Func) return boolToValue(ok) } // 等値の判定 func eql(x, y Value) Value { switch a := x.(type) { case Func: return Int(0) case Vec: return Int(0) default: return boolToValue(a == y) } } // リスト関連 func pair(v Value) Value { _, ok := v.(*Cell) return boolToValue(ok && v != NIL) } func null(v Value) Value { return boolToValue(v == NIL) } func cons(x, y Value) Value { return newCell(x, y) } func car(v Value) Value { cp, ok := v.(*Cell) if !ok { panic(fmt.Errorf("car: List required, %v", v)) } return cp.car } func cdr(v Value) Value { cp, ok := v.(*Cell) if !ok { panic(fmt.Errorf("cdr: List required, %v", v)) } return cp.cdr } func setCar(v, x Value) Value { cp, ok := v.(*Cell) if !ok { panic(fmt.Errorf("setCar: List required, %v", v)) } cp.car = x return x } func setCdr(v, x Value) Value { cp, ok := v.(*Cell) if !ok { panic(fmt.Errorf("setCdr: List required, %v", v)) } cp.cdr = x return x } // 時間 func clock() Value { return Int(time.Now().UnixNano()) } func since(v Value) Value { x, ok := v.(Int) if !ok { panic(errorInt("since: ", v)) } y := time.Now().UnixNano() return Str(time.Duration(y - int64(x)).String()) } // エラー func userError(v Value) Value { panic(fmt.Errorf("%v", v)) } // 入力 func input(mes Value) Value { var lex Lex lex.Init(os.Stdin) print(mes) lex.getToken() e := expression(&lex) return e.Eval(nil) } func initFunc() { funcTable["sqrt"] = Func1(math.Sqrt) funcTable["sin"] = Func1(math.Sin) funcTable["cos"] = Func1(math.Cos) funcTable["tan"] = Func1(math.Tan) funcTable["sinh"] = Func1(math.Sinh) funcTable["cosh"] = Func1(math.Cosh) funcTable["tanh"] = Func1(math.Tanh) funcTable["asin"] = Func1(math.Asin) funcTable["acos"] = Func1(math.Acos) funcTable["atan"] = Func1(math.Atan) funcTable["atan2"] = Func2(math.Atan2) funcTable["exp"] = Func1(math.Exp) funcTable["pow"] = Func2(math.Pow) funcTable["log"] = Func1(math.Log) funcTable["log10"] = Func1(math.Log10) funcTable["log2"] = Func1(math.Log2) funcTable["print"] = FuncV1(print) funcTable["println"] = FuncV1(println) funcTable["len"] = FuncV1(length) funcTable["vector"] = FuncV2(makeVector) funcTable["isInt"] = FuncV1(isInt) funcTable["isFlt"] = FuncV1(isFlt) funcTable["isStr"] = FuncV1(isStr) funcTable["isVec"] = FuncV1(isVec) funcTable["isFunc"] = FuncV1(isFunc) funcTable["eql"] = FuncV2(eql) funcTable["pair"] = FuncV1(pair) funcTable["null"] = FuncV1(null) funcTable["cons"] = FuncV2(cons) funcTable["car"] = FuncV1(car) funcTable["cdr"] = FuncV1(cdr) funcTable["setCar"] = FuncV2(setCar) funcTable["setCdr"] = FuncV2(setCdr) funcTable["clock"] = FuncV0(clock) funcTable["since"] = FuncV1(since) funcTable["error"] = FuncV1(userError) funcTable["input"] = FuncV1(input) funcTable["force"] = FuncV1(force) } // // 字句解析 // type Lex struct { scanner.Scanner Token rune } func (lex *Lex) getToken() { lex.Token = lex.Scan() switch lex.Token { case scanner.Ident: key, ok := keyTable[lex.TokenText()] if ok { lex.Token = key } case '=': if lex.Peek() == '=' { lex.Next() lex.Token = EQ } case '!': if lex.Peek() == '=' { lex.Next() lex.Token = NE } else { lex.Token = NOT } case '<': if lex.Peek() == '=' { lex.Next() lex.Token = LE } else { lex.Token = LT } case '>': if lex.Peek() == '=' { lex.Next() lex.Token = GE } else { lex.Token = GT } } } // // 構文解析 // // 仮引数の取得 func getParameter(lex *Lex) []Variable { e := make([]Variable, 0) if lex.Token != '(' { panic(fmt.Errorf("'(' expected")) } lex.getToken() if lex.Token == ')' { lex.getToken() return e } for { if lex.Token == scanner.Ident { e = append(e, Variable(lex.TokenText())) lex.getToken() switch lex.Token { case ')': lex.getToken() return e case ',': lex.getToken() default: panic(fmt.Errorf("unexpected token in parameter list")) } } else { panic(fmt.Errorf("unexpected token in parameter list")) } } } // 引数の取得 func getArgs(lex *Lex) []Expr { e := make([]Expr, 0) if lex.Token != '(' { panic(fmt.Errorf("'(' expected")) } lex.getToken() if lex.Token == ')' { lex.getToken() return e } for { e = append(e, expression(lex)) switch lex.Token { case ')': lex.getToken() return e case ',': lex.getToken() default: panic(fmt.Errorf("unexpected token in argument list")) } } } // if 式の解析 func makeSel(lex *Lex) Expr { testForm := expression(lex) if lex.Token == THEN { lex.getToken() thenForm := expression(lex) switch lex.Token { case ELSE: lex.getToken() elseForm := expression(lex) if lex.Token != END { panic(fmt.Errorf("if, 'end' expected")) } lex.getToken() return newSel(testForm, thenForm, elseForm) case END: lex.getToken() return newSel(testForm, thenForm, Int(0)) default: panic(fmt.Errorf("if, 'else' or 'end' expected")) } } else { panic(fmt.Errorf("if, 'then' expected")) } } // begin 式の解析 func getBody(lex *Lex) []Expr { body := make([]Expr, 0) for { body = append(body, expression(lex)) switch lex.Token { case ',': lex.getToken() default: return body } } } func makeBegin(lex *Lex) Expr { if lex.Token == END { panic(fmt.Errorf("invalid begin form")) } body := getBody(lex) if lex.Token != END { panic(fmt.Errorf("'end' expected")) } lex.getToken() return newBgn(body) } // while 式の解析 func makeWhile(lex *Lex) Expr { testForm := expression(lex) if lex.Token == DO { lex.getToken() return newWhl(testForm, makeBegin(lex)) } else { panic(fmt.Errorf("'do' expected")) } } // let 式の解析 func makeLet(lex *Lex) Expr { vars := make([]Variable, 0) vals := make([]Expr, 0) for { e := expression(lex) a, ok := e.(*Agn) if !ok { panic(fmt.Errorf("let: invalid assign form")) } vars = append(vars, a.name) vals = append(vals, a.expr) if lex.Token == IN { break } else if lex.Token != ',' { panic(fmt.Errorf("let, 'in' or ',' expected")) } lex.getToken() } lex.getToken() return newLet(vars, vals, makeBegin(lex)) } // 添字の取得 func getIndex(lex *Lex) []Expr { xs := make([]Expr, 0) lex.getToken() for { e := expression(lex) if lex.Token != ']' { panic(fmt.Errorf("']' expected")) } xs = append(xs, e) lex.getToken() if lex.Token != '[' { return xs } lex.getToken() } } // 因子 func factor(lex *Lex) Expr { switch lex.Token { case '(': lex.getToken() e := expression(lex) if lex.Token != ')' { panic(fmt.Errorf("')' expected")) } lex.getToken() return e case '[': lex.getToken() xs := getBody(lex) if lex.Token != ']' { panic(fmt.Errorf("']' expected")) } lex.getToken() return newCrv(xs) case '+': lex.getToken() return newOp1('+', factor(lex)) case '-': lex.getToken() return newOp1('-', factor(lex)) case NOT: lex.getToken() return newOp1(NOT, factor(lex)) case IF: lex.getToken() return makeSel(lex) case BGN: lex.getToken() return makeBegin(lex) case WHL: lex.getToken() return makeWhile(lex) case LET: lex.getToken() return makeLet(lex) case FN: lex.getToken() xs := getParameter(lex) body := makeBegin(lex) clo := newClo(xs, body) if lex.Token == '(' { ys := getArgs(lex) if len(xs) != len(ys) { panic(fmt.Errorf("wrong number of arguments: fn")) } return newAppV(clo, ys) } return clo case LIST: lex.getToken() if lex.Token == '(' { return newList(getArgs(lex)) } panic(fmt.Errorf("List: '(' expected")) case CALL: lex.getToken() xs := getArgs(lex) if len(xs) == 0 { panic(fmt.Errorf("wrong number of arguments: call")) } return newAppV(xs[0], xs[1:]) case DELAY: lex.getToken() if lex.Token != '(' { panic(fmt.Errorf("delay: '(' expected")) } lex.getToken() e := expression(lex) if lex.Token != ')' { panic(fmt.Errorf("delay: ')' expected")) } lex.getToken() return newMakePromise(e) case scanner.Int: var n int64 fmt.Sscan(lex.TokenText(), &n) lex.getToken() return Int(n) case scanner.Float: var n float64 fmt.Sscan(lex.TokenText(), &n) lex.getToken() return Flt(n) case scanner.String: var s string fmt.Sscanf(lex.TokenText(), "%q", &s) lex.getToken() return Str(s) case scanner.Ident: name := lex.TokenText() lex.getToken() if name == "quit" { panic(name) } v, ok := funcTable[name] if ok { if lex.Token == '(' { xs := getArgs(lex) if len(xs) != v.Argc() { panic(fmt.Errorf("wrong number of arguments: %v", name)) } return newApp(v, xs) } else { // 関数値をそのまま返す return v } } else if lex.Token == '[' { return newRef(Variable(name), getIndex(lex)) } else if lex.Token == '(' { // 変数に格納されている関数を呼び出す return newAppV(Variable(name), getArgs(lex)) } else { return Variable(name) } default: panic(fmt.Errorf("unexpected token: %v", lex.TokenText())) } } // 項 func term(lex *Lex) Expr { e := factor(lex) for { switch lex.Token { case '*': lex.getToken() e = newOp2('*', e, factor(lex)) case '/': lex.getToken() e = newOp2('/', e, factor(lex)) case '%': lex.getToken() e = newOp2('%', e, factor(lex)) default: return e } } } // 式 func expr3(lex *Lex) Expr { e := term(lex) for { switch lex.Token { case '+': lex.getToken() e = newOp2('+', e, term(lex)) case '-': lex.getToken() e = newOp2('-', e, term(lex)) default: return e } } } // 比較演算子 func expr2(lex *Lex) Expr { e := expr3(lex) x := lex.Token switch x { case EQ, NE, LT, GT, LE, GE: lex.getToken() return newOp2(x, e, expr3(lex)) default: return e } } // 論理演算子 func expr1(lex *Lex) Expr { e := expr2(lex) for { x := lex.Token switch x { case AND, OR: lex.getToken() e = newOps(x, e, expr2(lex)) default: return e } } } func expression(lex *Lex) Expr { e := expr1(lex) if lex.Token == '=' { switch x := e.(type) { case Variable: lex.getToken() return newAgn(x, expression(lex)) case *Ref: lex.getToken() return newUdt(x, expression(lex)) default: panic(fmt.Errorf("invalid assign form")) } } return e } // ユーザ関数の定義 func defineFunc(lex *Lex) string { lex.getToken() if lex.Token != scanner.Ident { panic(fmt.Errorf("invalid define form")) } name := lex.TokenText() lex.getToken() xs := getParameter(lex) v, ok := funcTable[name] if ok { switch f := v.(type) { case *FuncU: if len(f.xs) != len(xs) { panic(fmt.Errorf("wrong number of arguments: %v", name)) } body := newBgn(getBody(lex)) if lex.Token != END { panic(fmt.Errorf("'end' expected")) } f.xs = xs f.body = body default: panic(fmt.Errorf("%v is built-in function", name)) } } else { // 再帰呼び出し対応 f := newFuncU(name, xs, nil) funcTable[name] = f f.body = newBgn(getBody(lex)) if lex.Token != END { delete(funcTable, name) panic(fmt.Errorf("'end' expected")) } } return name } // ライブラリのロード func loadLib(name string) { var lex Lex file, err := os.Open(name) if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } defer func(){ err := recover() file.Close() if err != nil { fmt.Fprintf(os.Stderr, "%s: %v, %s\n", name, err, lex.Position) os.Exit(1) } }() lex.Init(file) for { lex.getToken() if lex.Token == scanner.EOF { break } else if lex.Token == DEF { defineFunc(&lex) } else { e := expression(&lex) if lex.Token != ';' { panic(fmt.Errorf("invalid expression")) } e.Eval(nil) } } } // 式の入力と評価 func toplevel(lex *Lex) (r bool) { r = false defer func(){ err := recover() if err != nil { mes, ok := err.(string) if ok && mes == "quit" { r = true } else { fmt.Fprintln(os.Stderr, err) for { c := lex.Peek() if c == '\n' { break } lex.Next() } } } }() for { fmt.Print("Calc> ") lex.getToken() if lex.Token == DEF { fmt.Println(defineFunc(lex)) } else { e := expression(lex) if lex.Token != ';' { panic(fmt.Errorf("invalid expression")) } else { println(e.Eval(nil)) } } } return r } func main() { initKeyTable() initFunc() makeNIL() for _, name := range os.Args[1:] { loadLib(name) } var lex Lex lex.Init(os.Stdin) for { if toplevel(&lex) { break } } }