Javascriptでデータ構造を再帰的に定義する必要があります。循環リンクリストの簡単な例を次に示します。
// List a very simplified example of what the actual (non list) code does.
function List(f, r) {
return function(){ return [f, r]; };
}
var first = function (l){ return l()[0]; }
var rest = function (l){ return l()[1]; }
var head = List('a', List('b', List('c', head)));
これが実行されると、リスト'c'のヘッドは、必要に応じてリスト' a'ではなく、未定義に解決されます。Listは、関数を返す関数の例です(これは、追加できるJavascriptリストではありません)。
ヘッドの定義をラップしようとしましたが、それは自己実行の名前付き関数ですが、ヘッドが解決されたときにスタックを吹き飛ばしました。
私が見落としているJavascriptスタイルのソリューションは何ですか?
試み
浮気して、私はうまくいくかもしれないいくつかのコードを思いついた:
var f = function(){
var value;
return function(v){
if (value === undefined)
value = v
return value.apply(undefined, arguments);
};
};
var tempHead = f();
var head = List('a', List('b', List('c', tempHead)));
tempHead(head);
first(head); // a
first(rest(head)) // b
first(rest(rest(head))) // c
first(rest(rest(rest(head)))) // a
first(rest(rest(rest(rest(head))))) // b
...
しかし、これは本当に醜いです。より良い解決策はありますか?
解決
user1689607は、実装の一部を隠すためにカプセル化した優れたソリューションを思いつきました。
var def = function(name, impl) {
var value;
return value = impl.apply(Object.defineProperty({}, name, {
'value': function() { return value.apply(this, arguments); }
}));
};
function List(f, r) {
return function(){ return [f, r]; };
}
function first(l){ return l()[0]; }
function rest(l){ return l()[1]; }
var circle = def('head', function() {
return List('a', List('b', List('c', this.head)));
});
first(circle); // 'a'
first(rest(circle)); // 'b'
first(rest(rest(circle))); // 'c'
first(rest(rest(rest(circle)))); // 'a'
first(rest(rest(rest(rest(circle))))); // 'b'
もう1つの更新では、スコープを変更する代わりに、自己参照を明示的に渡すことになりました。
var def = function(impl) {
var value;
return (value = impl(function() { return value.apply(this, arguments); }));
};
var circle = def(function(self) {
return List('a', List('b', List('c', self)));
});
このコードはparse.jsで使用されます。