ランダムな関数実行

Mochikit を使って、複数の関数をランダムに呼ぶ関数、というのを作ってみました。

function randcall(/*f1, f2, f3...*/) {
  var f = partial(compose(next, irand), arguments);
  return function() {
    return f().apply(this, arguments);
  };
}

短い中に Mochikit の関数的な要素を活用しています。まず関数合成 (compose) と引数の部分適用 (partial) を組み合わせて

next(irand(arguments))

を実行する手前の状態を作っています (f)。

"irand" は配列 (的なもの) をランダムに取り出すイテレータで、mala さんによる実装Mochikit 用に移植したものです (省略します) 。

それに "next" 関数を適用することで「引数をランダムに一つだけ取り出す」という操作を行うわけです。さらに "partial" で予め "irand" への引数を固定しています。

スコープをまたいで arguments オブジェクト (関数のリスト) を利用しているわけですが、arguments を別の変数に割り当てておく必要はありません。partial の有効な利用法と言えるでしょう。

返り値は、任意の引数を、ランダムにピックアップした関数に渡す、という関数です。


さて、作ってはみたものの、用途があまり思い浮かびません (笑。

が、例えばある出力関数が複数の出力先を取れる場合に、それぞれの出力先にバインドした関数を渡しておき、ランダムな場所に出力させる、という使い方が可能だと思います (ここで言う「出力先」には DOM 要素や配列等が考えられます)。

例として気まぐれな配列 push の使用例をアレンジしたものをお見せします。

例 1 (ある配列のデータを三つの配列に振り分ける):

function pusher(a) {
  return function(x) {
    a.push(x);
  };
}
var a = [], pa = pusher(a);
var b = [], pb = pusher(b);
var c = [], pc = pusher(c);

forEach(
  large_list,
  randcall(pa, pb, pc)
);  

例 2 (同様に、データを三つの配列に振り分ける):

// 略
var rc = randcall(pa, pb, pc);
responseText.replace(/<a href="(.+?)"/g, function(_, $1) {
  rc($1);
});

あ、じゃんけんのプログラムも作れそうですね。