Javascript で Read-Eval-Print-Loop を一緒にハックしようとしています。(これは Web ベースの「Javascript を教える」プラットフォーム用です。) ほとんど動作するものがありますが、閉鎖に関する奇妙なバグに遭遇しています。
これは、ループのコアの簡略化されたバージョンです。で作成された状態を維持するためにクロージャーと継続を使用したいので、このように書きましたeval
。
// listing 1
var repl = function(result) {
return {
result:
result,
then:
function (expression, continuation) {
return continuation(eval(expression));
},
};
}
そして、それはほとんど機能します。たとえば、式var x = 1
、x++
、のシーケンスを正しく評価しx
ます。
// listing 2
repl(eval('var x = 1')).then('x++', repl)
.then('x', repl)
.result
// evaluates to 2
したがって、式は、グローバル スコープを汚染することなく、以前に宣言されたローカル変数にアクセスして変更できます。これは素晴らしいことです。 しかし、変数宣言 (つまりvar ...
) は、チェーンの最初の式に対してのみ機能します。 たとえば、一連の式var x = 1
, var y = 2
,はy is not definedエラーをy
スローします。
// listing 3
repl(eval('var x = 1')).then('var y = 2', repl)
.then('y', repl)
.result;
// throws "y is not defined"
repl
次のように、各インスタンスをその定義に置き換えると、このエラーを回避できることがわかりました。
//listing 4
//
// same as listing 3, but repl is replaced with its
// definition from listing 1
function (result) {
return {
result:
result,
then:
function (expression, continuation) {
return continuation(eval(expression));
}
},
})(eval('var x = 1')).then(
'var y = 2',
function (result) {
return {
result:
result,
then:
function (expression, continuation) {
return continuation(eval(expression));
},
};
}
).then(
'y',
function (result) {
return {
result:
result,
then:
function (expression, continuation) {
return continuation(eval(expression));
},
};
}
).result
// evaluates to 2
これは 2 に評価されます。したがって、各反復eval
の定義を ing するだけで問題を解決できると思います。repl
しかし、確かにもっと良い解決策があります...そうではありませんか?
編集:の各インスタンスを に置き換えてみましrepl
たeval('('+repl+')')
が、問題は解決しませんでした。私は何が欠けていますか?