CodeIQ:姿 (変数名) を 隠す

私自身が表題の問題を解いた時のプログラムについて解説します。
問題の詳細は「姿 (変数名) を 隠す」(CodeIQ)を参照してください。

問題の概要

問題を引用します。
var factorial = function (n) {
    'use strict';
    if (n === 1) {
        return 1;
    }
    return n * factorial(n - 1);
};
console.log(factorial(10));
								
というコードがあるとします。
変数名の使用を避けたい状況(関数を宣言、定義せずに(var factorial = function (n) {…};とfunciton factorial(n) {…} のいずれも使わずに。)すなわち関数に名前をつけない状況。)になった場合、同様のことをするプログラムをどのように記述すればいいか考えてください。(ただし、再帰構造はそのままで。)

私のプログラム

Javascript(NodeJs)で解答しています。

console.log(
	(function(f) {
		'use strict';
		return (function(x) {
			return f(function(y) {
				return x(x)(y);
			});
		})(function(x) {
			return f(function(y) {
				return x(x)(y);
			});
		});
	})(function(f) { return function(n) { return n == 0 ? 1 : n * f(n - 1); }; })(10)
);

解説

無名関数をどうやって再帰するかという問題です。
無名関数には名前がないので再帰呼び出し時に関数名を使えないため何らかの方法でそれを実現しなければなりません。

()

この問題では定義した無名関数を即時実行しなければなりません。それができないと一度変数にとって呼び出す必要があるため問題の仕様を満たせないのです。
その手段が無名関数を(カッコ)で囲むという方法です。

// 10と出力される
(function(n){
	console.log(n);
})(10);

これで、無名関数の引数n=10で即時実行されます。
この方法はJavaScriptでクラスのようなものを作るときにも使います。

もうひとつの回答

解答のコードは2つ目に書いたコードで、最初(提出しませんでしたが)別のコードを書きました。

console.log(
	(function(n){
		if(n == 1){
			return 1;
		}
		return n*arguments.callee(n-1);
	})(10)
);

解答のコードよりも短く、わかりやすいです。
問題の関数を無名関数にして即時呼び出ししています。無名関数を再帰呼び出しするためarguments.callee()を使用します。

ただ、1点気になる点があってこのコードは提出しませんでした。
それは元のコードが'use strict'なことです。
問題には'use strict'が条件とは書いてないのでこれでも良いのかわかりませんが、callee()はstrictモードでは使用できません。問題は元のコードを無名関数にせよということなのでstrictも考慮することにしました。

Zコンビネータ

やり方がわからないので調べたらWikipwdiaにそのもののコードがありました。ただし、WikipediaのZコンビネータは名前付きの関数になっているので、それも無名関数にしています。ついでに'use strict'も追加しています。

ただし、このZコンビネータですが全然わかりません。ぱっと見、わかるのはfunctionを返す関数だということだけです。しかし、複雑すぎてどういう関数が返るのかよくわかりません。
デバッガで追いかけると、nの値はZコンビネータに適用されて10,9,…,2,1,0となりながら実行されており、確かに再帰呼び出しされています。
でも、よくわかりません。

雑感

このZコンピネータ、ナチュラルにわかる人っているんでしょうか? いるんだろうな。
私にはカリー化の概念を使って、入力された無名関数(function(n) { return n == 0 ? 1 : n * f(n - 1); })にn-1〜0までを順次適用しながら部分関数を順次返して行ってるのだろうという想像くらいしかできません。