とりあえず、以下のようにしたら、動作させることはできた。
おおまかな流れを把握するので精一杯だった。
式の評価とか、なんらかの構造をもつものについてのアルゴリズムは、複雑になりやすいので、こういった方法で少しでも、整理してプログラミングをしていくということなのでしょう。。。
①add(amb(リスト1),amb(リスト2))がdirverの中のcalculateの第1引数へ
②calculateの中のmatchにより、add:(x,y)にマッチ
③その中で再帰でcalculateの第1引数へ amb(リスト)の形なので
④amb:(choice)にmatch また再帰でcalculateの第1引数へ headであるnum()の形で
⑤最終的には num:(n)にmatch return contiuesOnSuccess(n,contiunesOnFailure);
に到達する。 contiuesOnSuccessは第1引数anyvalue(今の場合n)をそのまま返している。suspendedComputationにはfailureのほうにある残りのリストが保持されることになるらしい。
代数的データ構造のパターンマッチについては、以前でてきた方法
var exp = {
match : (anExp, pattern) => {
return anExp.call(exp, pattern);
},
amb : (alist) => {
return (pattern) => {
return pattern.amb(alist);
};
},
num : (n) => {
return (pattern) => {
return pattern.num(n);
};
},
add : (exp1, exp2) => {
return (pattern) => {
return pattern.add(exp1, exp2);
};
}
};
評価関数
var calculate = (anExp, continuesOnSuccess, continuesOnFailure) => {
return exp.match(anExp, {
※数値の場合 num: (n) => {
return continuesOnSuccess(n, continuesOnFailure);
},
※足し算の場合 add: (x, y) => {
return calculate(x, (resultX, continuesOnFailureX) => {
return calculate(y, (resultY, continuesOnFailureY) => {
引数xとyがともに成功すれば、両者の値で足し算を計算
return continuesOnSuccess(resultX + resultY, continuesOnFailureY);
}, continuesOnFailureX);
y の計算に失敗すれば、xの失敗継続を渡す
}, continuesOnFailure);
x の計算に失敗すれば、おおもとの失敗継続を渡す
},
※amb式の場合 amb: (choices) => {
var calculateAmb = (choices) => {
return list.match(choices, {
empty: () => {
return continuesOnFailure();
},
cons: (head, tail) => {
return calculate(head, continuesOnSuccess, (_) => {
失敗継続で後尾を計算
return calculateAmb(tail);
});
}
});
};
return calculateAmb(choices);
}
});
};
非決定計算機の駆動関数
var driver = (expression) =>{
var suspendedComputation = null;//中断された計算を継続として保存する変数
成功継続
var continuesOnSuccess = (anyValue,
continuesOnFailure) => {//再開に備えて、失敗継続を保存
suspendedComputation = continuesOnFailure;
return anyValue;
};
失敗継続
var continuesOnFailure = () => {
return null;
};
内部に可変な状態suspendedComputationを持つクロージャーを返す
return () => { //中断された継続がなければ、最初から計算
if(suspendedComputation === null) {
return calculate(expression, continuesOnSuccess, continuesOnFailure);
} else { //中断された継続があれば、その継続を実行
return suspendedComputation();
}
};
};
リストモジュールも必要
// expect(array).to.an('array');はコメントアウトしないとだめだった。
テスト
var ambExp = exp.add(
exp.amb(list.fromArray([exp.num(1),exp.num(2)])),
exp.amb(list.fromArray([exp.num(3),exp.num(4)])));
var calculator = driver(ambExp);
calculator() ;
calculator() ;
calculator() ;
calculator() ;
0 件のコメント:
コメントを投稿