function hoge(){ と hoge = function(){ の違いが相変わらずわからん。 - ・・・tohokuaikiのチラシの裏(それ図解できたらいいなぁ)において、id:minahito_carpから詳細なコメントをもらってしばらく考えた。
もの凄い原始的な話をすれば、サブルーチン名というのは、サブルーチンの命令が書かれているメモリの先頭アドレスにつけられたラベル(シンボル)の名前だったりするのです。(中略)
アドレスを変数に格納すれば、元のサブルーチン名を知らなくてもサブルーチンを呼ぶことができます。これが関数ポインタ、ファンクタ、デリゲート、関数型等の仕組みです。この理屈上、言語仕様がそれをOKにすればサブルーチンの定義と同時にそれを変数に格納することでシンボルの定義(サブルーチン名)はいらないということになります。これがラムダです。
ワタシはプログラミングを始めたのが社会人になってからなのでか、よく覚えてるんだけど。
プログラムの練習って最初に±の演算子とかやって、ifの条件分岐やって、次くらいに関数ってのをやった気がする。
なんで、関数=定義するみたいな印象。それが変数に入るっていうのはなんかすごい不思議な気もしたんだけど、
<?php function hogehoge(){ echo "hoge!! \n"; } $exec_func = 'hogehoge'; $exec_func();
なんてのは、わりとすっと入ってきた。だけど、JavaScriptなんかで
var hoge = []; for (var i=0,j=10; i<j; i++){ var hoge[i] = function(){ return function(){ alert("hoge" + i ); } } }
とかいうのは結構面食らった。なんでfunctionをreturnしているんか全然理解できんかった。
それは結局やっていくうちに「あぁ、そういうもんだな」って気になってきたんだけど、結局「変数=Functionそのもの」っていう扱いができるかできないかっていうだけだったんだな。PHPの例の場合は「変数=Functionのアドレス(的なもの)」っていうのとの違い。
関数そのものだから、局所化された値もそのまま持っている。これがクロージャの性質。これはすごい便利。
そもそも関数化する目的って・・・・
最初に関数を勉強するときに
- プログラムには、関数(サブルーチン)っていうのがあって、これを定義すると何度も同じ処理を書かなくて便利ですよ
って意識だった。
だけど、関数化するってことは
- 変数の領域がぶつかることを考えなくていい
- ロジックを明確化できる
っていう目的もあるんだってことに後々気づいた。
ただ、実際に関数を使ってプログラミングしていくと、
- 同じ処理を何度も・・・・ → 実際は「ちょっと違った」たくさんの関数を書くケースがママある。
- ロジックの明確化・・・・ → 実際は書いた本人以外は結構な量のコードを読まないといけない。
っていうことがよくある。
特に、「同じ処理を・・」のメリットのところは実際には1回しかコールされない関数だって多いし、そもそも何度もコールする関数なんかはいわゆるStaticなクラスでコールさせるものにしてしまっているから、経験的に(全体量からみると)結構少ない。
だけど、変数を局所化できるっていうメリットはすごく大きくて、これができるんなら他の関数の特長ってそれほどプライオリティ高くないんじゃないの?っていう気になる。
ラムダしかないスクリプト言語を触ると理屈がよく分かります。この場合、 "大域関数" という概念がないので、グローバル変数にサブルーチンを入れて、大域関数として扱います。グローバル変数の数値をどこからでもアクセスできるように、グローバル変数に入っているサブルーチンをどこからでも使うことができます。
ラムダしかないスクリプト言語っていうのは、なんかそんな感じじゃないかな。「関数名空間なんて要らねー」って。
結局、関数名なんて、グローバル変数と変わらんからそっから呼び出せよっていう。「関数定義」っていう変数名空間を確保する意味なんてないんじゃないの?って。
JavaScriptの「function hoge(){ と hoge = function(){」だって、結局同じことだよね。
「変わんない」ってことで。いや、変わるんだけど、それは定義している空間が違うんだけど、Callするときは同じ書き方でCallするから「変わんない」(ように見える)ってこと。
あぁ、納得ができた。。。