前回の続きで、塗り分けの時にモナド的に書きたいなと言っていたところを、無い知恵を絞ってモナドもどきを作ってみた。
var Result = {
False: {
bind: function() {
return this;
},
get: function() {
return false;
}
},
True: {
bind: function(f) {
return f();
},
get: function() {
return true;
}
},
Undefined: {
bind: function(f) {
var result = f();
if(result.get() === false) {
return result;
}
return Result.Undefined;
},
get: function() {
return undefined;
}
}
}
これを使うと、「与えられた要素が全て互いに異なる」という条件はこう書ける。
モナドを使いつつも、あまり関数型っぽくない書き方だが、実行効率を踏まえつつハイブリッドなやり方と言うことで
function AllNotEqual() {
return allNotEqual(arguments, arguments.length-2);
}
function allNotEqual(items, iter) {
var result = (function(j) {
var callee = arguments.callee;
if(j <= iter + 1) return NotEqual(items[iter], items[j]);
return NotEqual(items[iter], items[j]).bind(function() { return callee(j-1); });
})(items.length - 1);
if(iter <= 0) {
return result;
}
return result.bind(function() { return allNotEqual(items, iter-1); });
}
function NotEqual(x, y) {
var tmp_x = x.get(), tmp_y = y.get();
if(tmp_x === undefined || tmp_y === undefined)
return Result.Undefined;
if(tmp_x != tmp_y)
return Result.True;
return Result.False;
}
Sudoku の条件である、「各行、各列、各3x3のブロックで同じ数字を使わない」は、関数型言語の勉強の時に作った do 記法もどきを利用してこう書ける。
ちとながいが、よく見れば単にルールをべた書きしただけの記述。
var MonaDo = function(fs) {
var monado = function(funcs) {
if(funcs.length > 1) {
var inner = monado(funcs.slice(1));
return function(a) {
return funcs[0](a).bind(inner);
}
}
return funcs[0];
}
return monado(fs)();
}
function RowNotEqual(cells, row) {
return AllNotEqual.apply(this, cells[row]);
}
function ColNotEqual(cells, col) {
return AllNotEqual.apply(this, cells.map(function(row) {
return row[col];
}));
}
function BlkNotEqual(cells, row, col) {
return AllNotEqual(
cells[row][col], cells[row][col+1], cells[row][col+2],
cells[row+1][col],cells[row+1][col+1],cells[row+1][col+2],
cells[row+2][col],cells[row+2][col+1],cells[row+2][col+2]);
}
var Condition = function() {
return MonaDo([
function() {return RowNotEqual(Cells, 0); },
function() {return RowNotEqual(Cells, 1); },
function() {return RowNotEqual(Cells, 2); },
function() {return RowNotEqual(Cells, 3); },
function() {return RowNotEqual(Cells, 4); },
function() {return RowNotEqual(Cells, 5); },
function() {return RowNotEqual(Cells, 6); },
function() {return RowNotEqual(Cells, 7); },
function() {return RowNotEqual(Cells, 8); },
function() {return ColNotEqual(Cells, 0); },
function() {return ColNotEqual(Cells, 1); },
function() {return ColNotEqual(Cells, 2); },
function() {return ColNotEqual(Cells, 3); },
function() {return ColNotEqual(Cells, 4); },
function() {return ColNotEqual(Cells, 5); },
function() {return ColNotEqual(Cells, 6); },
function() {return ColNotEqual(Cells, 7); },
function() {return ColNotEqual(Cells, 8); },
function() {return BlkNotEqual(Cells, 0, 0); },
function() {return BlkNotEqual(Cells, 0, 3); },
function() {return BlkNotEqual(Cells, 0, 6); },
function() {return BlkNotEqual(Cells, 3, 0); },
function() {return BlkNotEqual(Cells, 3, 3); },
function() {return BlkNotEqual(Cells, 3, 6); },
function() {return BlkNotEqual(Cells, 6, 0); },
function() {return BlkNotEqual(Cells, 6, 3); },
function() {return BlkNotEqual(Cells, 6, 6); }
]).get()
};
0 件のコメント:
コメントを投稿