これってようするにローカル関数定義できるかどうかと変数のスコープをどう解決するかってことだよね
http://d.hatena.ne.jp/lethevert/20070528/p2
「ボクも知ってるあのマイナー言語でいろいろ書いてネタにしてみよー」と漠然と思っていたけれど、そんなにマイナーな言語など特に知らないのでした。ざんねん。
というわけで特にマイナーでもない言語を2つほど。ひとつめは Lua。
function f(x) local function g(y) return x + y end local function h(x) return g(10) end return h end
JavaScript によく似てますね……って思ったけどそれって function っていうキーワードだけ?な気もしてきた。特に注目するポイントは local かな。 local 宣言のされていない変数に何かの値を代入したりすると、グローバル環境への操作とみなされるため、ここで local を省くと g と h は(fを最初に実行したときに)グローバル環境で定義されてしまいます(Ruby の「defのなかのdef」みたいな感じね)。
もうひとつは Erlang。 Erlang には関数内で関数を定義するという方法がありませんが、関数リテラルを変数に束縛するという方法で強引に解決できないこともありません。
f(X) -> G = fun(Y) -> X + Y end, H = fun(X) -> G(10) end, H.
対応づけのために H への束縛を作ってから H を返していますが、もちろん fun (X) -> ... で終了にしてしまっても構いません。
さて、この関数を呼ぶと、
1> c(test). ./test.erl:6: Warning: variable 'X' is unused ./test.erl:6: Warning: variable 'X' shadowed in 'fun' 2> test:f(10)(1). ** 1: syntax error before: '(' **
警告を出してくれるのは嬉しいのですが、それはさておき関数を呼べません。どうも何やら不思議な優先順位に従って構文が解析されているようですね。
2> (test:f(10))(1). 20
こうしないといけません。
というわけで、個人的にけっこう気に入っているんですがいまいちちゃんと使ってみたことがない Lua と、なんだかんだいってもいろんな構文に萎え要素が満載な Erlang でした。
あーあとそういえばマイナーでもなんでもないけど挙がってないやつだと Common Lisp ならこんな感じ?
(defun f (x) (labels ((g (y) (+ x y)) (h (x) (g 10))) #'h))
CL-USER> (funcall (f 10) 1) 20
局所定義に defun は使えないので labels を使う。敢えて labels ではなく let を使うなら、
(defun f (x) (let* ((g (lambda (y) (+ x y))) (h (lambda (x) (funcall g 10)))) h))
ってところか?(正しくは #'(lambda ...) なのかな)
ところで「世の中でもっとも普及した Common Lisp 処理系は xyzzy だ」というのはどうだろう(たぶん嘘)。