ねぇうしくんうしくん

今週のまとめ (一週間で自分が見た技術系サイトのログ)が今のところメインです。プログラミング言語、人工知能、セキュリティ 等

ダイナミックスコープをレキシカルスコープに直す。

2016年に作った Lisp (Scheme) インタプリタ、ダイナミックスコープだったまま放置していたのでレキシカルスコープに直した。

ダイナミックスコープとレキシカルスコープとは。

スコープの変数の参照のやり方の違い。

  • ダイナミックスコープ:実行時に呼び出し側 (caller) の環境を参照する。
  • キスカルスコープ:構文上で外側にあるスコープを参照する。

例を挙げると

(define x 123)
(define (f) x)
(let ((x 456)) (print (f)))

のようなコードでは、ダイナミックスコープでは 456 、レキシカルスコープでは 123 である。

大体の言語はレキシカルスコープで実装されている。わかりやすいので。

どうしてダイナミックスコープで実装してしまったか。

実行時の関数呼び出しを評価する際になって初めて環境オブジェクトを生成していた。よって外側の参照を行う際、呼び出し元の環境を遡って参照する=ダイナミックスコープになっていた。

kantele/eval.js at d85caa71fb5206f93b0912b9582e07f3bdb2003c · 45deg/kantele · GitHub

修正

関数(あるいはスコープ)が作られる際に環境を埋め込む。いわゆるクロージャを作る。 完全なインタプリタ型で実装していたので思ったよりかなり楽に実装できた(関数オブジェクトのコンストラクタの引数に加えるだけ) *1

Fixed: dynamic scope -> lexical scope · 45deg/kantele@966ec24 · GitHub

*1: VM型の場合はクロージャを作るための命令を作る必要があるかも知れない