Deprecated: The each() function is deprecated. This message will be suppressed on further calls in /home/zhenxiangba/zhenxiangba.com/public_html/phproxy-improved-master/index.php on line 456
dankogai の Erlang 評に一言いうことにする - val it : α → α = fun
[go: Go Back, main page]

最新

val it : α → α = fun

<<  2007/05  >>

2007/05/21 dankogai の Erlang 評に一言いうことにする

http://blog.livedoor.jp/dankogai/archives/50832431.html PHP については反響が大きいみたいだが Erlang の反響のなさは言語の知名度の差だなと思う。マイナーな言語だと アホなことを書いてもバレないからいいですね。

わたしも Erlang の言語仕様はダサいと思っていてべつに擁護するつもりはさらさらない。ありゃダメだ。モデルの良さと、実装(処理系)の良さと、統語論の良さはまた別である。 Erlang は実装は凄いし、モデルもほかに例がないので面白いが、それとシンタックスの善し悪しはそりゃ、ぜんぜん別の話である。

でもまあ、ある人が「ダメだ」と主張していることそのものには同意するとしても、その内実が間違っているのはやっぱり気になる。以下で書くのはそういう話。

構文の一貫性のなさ

関数定義と receive が似たような構文なんて意味不明に見えるかもしれない。でも実は似たような構文を取るものはほかにある。case、 if、try..catch、それに fun だ。

なぜこれはどれも似たような構文を持っているか。それは似たようなことをするからだ。簡単に言うと「パターンマッチをして、ローカルな変数束縛を作り、対応する式のならびを評価する」ということ。一方、変数への束縛はパターンマッチとして実現されているので、これがぜんぜん違う構文であることはまったく正当である。

関数と変数の名前空間が異なるという点については、 Common Lisp だってそうだし、そんなに重要なことだとは思わない。ただし、アトムと関数名が似たような名前空間を使っていて個人的には微妙だと思うことはある。

「OOに慣れた身からすると構文糖衣が多すぎる」というのはどういう冗談なのかよくわからない。念のために書いておくと、 receive にしても case にしても try..catch にしても、もちろんメッセージ送信にしても、べつに構文糖衣ではなく、歴とした構文である。「構文が多い」という主張だと思ってみても、それほど多いという気はしない。smalltalk みたいに非常にミニマルなコンセプトの言語よりは遥かに多いが、たとえば Ruby よりはずっと少ない。

なぜ別の構文としたかったかというのも推測はできる。推測するに、初期の Erlang はもっと Prolog 寄りの言語だったんじゃないだろうか、とね。 pred(A, B) のような表記はあくまでも述語であり、メッセージの送受信とは区別した方がいいと考えたのかもしれない。別ものだから別の構文を使うことにしたというわけだ。もちろんこれはわたしの勝手な推測。

余談として、メッセージ送信に ! という演算子を使うのは今となっては盲腸のようなもので、必然性は特にないだろうと思うし、わたしもイマイチだと思う。 Termite はこれを受けて ! 関数(マクロ?)を使うようだけど、もっとわかりやすい名前の方がいいんじゃないのかな。

無名関数の構文

上で書いたように fun は(あまり知られていない/使われていないが)複数のパターンマッチを書ける。これは優秀な機能で、ほかの関数型言語でこれができるのは、わたしは OCaml しか知らない(しかも OCaml では通常は fun で、それができるのは function という別の構文だ。あれは何とかならんものか)。

end はもちろん、どこが終端なのかわかりやすくすること、および receive や case や if や try..catch と構文構造を整えるためである(関数定義だけ end がない。これの方が一貫性に乏しいという気がするが、あったらとてもジャマだと思う)。文句を言うのは簡単だが、代替のより優れた構文というのはそう簡単には思いつかないし、 Rubyist のわたしは end があることに積極的な不満を感じない(そういえば Lua も end で終わる言語だな)。

ちなみに fun(Arg) -> mod:func(Arg) end のようなタイプの関数は fun mod:func/1 のような代替記法があり、実用上はそれほど繁雑にはなりづらい。もっとも、この代替記法は実用的な局面ではさっぱり短くならないという弱点も持っているのだが。

export って

モジュールの外からでも見える関数定義を指定するのが export である。 dankogai 氏が(たぶん)お気に入りの Haskell も同じ仕様だがあれも export していないとでも考えていたのかな。よく知らないのだけど、こういう不満をぶつけるということは perl は export するとほかのモジュールからモジュール名プレフィクスなしにいきなり参照できるのだろうか。名前の衝突に無力すぎると思うのだが。

そして、これは指摘もされているが、もちろんよく使うなら import してモジュール名プレフィクスを省く。

ただ、そこは Haskell のモジュールシステムの方が優れている点もある。というのは、個人的にはモジュールに別名をつけたいところ。 lists なんて打ちづらいモジュールはイヤだから、どこかでこれに「l」という別名をつけて、 l:map とかしたいのだね。これ、 Haskell だけじゃなく ML 系言語もできる技だが、 Erlang にはできない(と思う)。

それから、一気にエクスポートするなら -compile(export_all) という手もある。省略したら自動的にぜんぶエクスポートという方が私としては好みだが、どちらにせよきちんと指定しなさいというのもわかる(しかしなぜ -compile なのかはよくわからない。 -export_all か、 -export(all) でいいと思うんだが)。 DRY でないという主張は確かにその通りだが、 DRY でかつ、どれを export するかしないかを決めるというエレガントな構文はわたしには思いつかない(ダサいところで private { .. } のような構文を用意することとか……?)。

.(period)と,(comma)と;(semicolon)を使い分けている理由

ピリオドは定義の終わり(かつシェルでは入力式の終わり)、カンマは「式の並び」の区切り文字(または関数の引数の区切り文字)、セミコロンは関数定義などの「節(clause)」の区切り文字。ちゃんと意味は決まっている。使いわけているというか、ぜんぜん違うものだからそこを一緒にしていいわけがない。 dankogai 氏は Perl についても「セミコロンとカンマを使い分けている理由がわからん」と言うのだろうか。それならばわたしも(同意はできないが)理解はできる。

でも、この一部は必要ないだろう、という主張はありうるし、この辺が「古くさい」「ダサい」とみなされる理由なんだろう。こういう記号の存在はバランスであって、たとえば Ruby だってメソッドの引数を区切るカンマは必要ないと思うが、あってくれた方が嬉しいような気がする。わたしの感覚からすると、 Erlang は適切なバランスより「ちょいダサい」といったところ。「あってもいい」けどちょっとださい。でもおかげさまで Emacs の erlang-mode はかなり良好に働いてくれるとも言える。

その他

コメントが % というとわたしは TeX を連想した。ま、でも、それはどちらでもいい。コメントのノーテーションが最低だと思う言語ナンバーワンを不動のものにしているのはわたしの中では OCaml で、ほかの言語は記号が違うだけでどれも似たりよったりだ。大した問題じゃない。

export が DRY でない話は上に書いた。

まとめ

だいたい dankogai 氏は自分がさして詳しくないものについて書くとき、自信はたっぷりだが書いてあることは出鱈目であることが多くて、わたしもこの記事は何かでたまたま見かけて読んでみたらいつも通り出鱈目だったのでスルーしていたのだが、下のようなことを書きたくなったので書くことにした。

Erlang は古い言語で、 Prolog 由来のところもあり、そうはいってもダサい構文はいっぱいある。パーサを楽にするためにダサくなってるんじゃないの、みたいなやつね。しかし、ここで dankogai 氏が挙げていることについていえば、半分以上にはそれなりの理由ってものがある。それに、この程度のことはそれほど問題視するようなところはなくて、「こういうものだ」と思えばそれで終わりだ。そんなに耐えがたいとまでは、わたしは思わなかった。まあ世の中には Ruby の do 〜 end が許せないという心の狭い人もいるようなのでわからないけれど。

むしろ問題なのはモデルの方だろう。現在のわたしたちのスレッドモデルとはまったく違うモデルだからだ。そこに魅力はあり、難しさもそこにある。萎えるポイントもそこにある。と思う。こんな構文とかどうでもいいところで萎えている場合じゃないだろう。

ところで Erlang の処理系は BEAM という仮想機械なんだから、誰かがもっとマシなコンパイラを書けば構文上の問題は解決されるはずである。それは誰かがチャレンジしてくれたらいいなあという気はする。でもそれは (Perl|Py|Ruby)/tk とはぜんぜん違う、「ふつうの人」に馴染み深い言語とはちがったものになるだろう。なぜなら、 Erlang の処理系は Erlang のモデルに特化しているからだ。ほかの言語でやっていること(たとえば共有する変数でデータの受け渡しをするとか)は禁止しなければいけなくなる。モデルが仕様を規定する。 Erlang のモデルは Perl や Ruby とはあまりにもかけ離れているから、そう簡単には取り込めない(というか取り込んだところで同じようには取り扱えないからややこしいことになる)だろう。

たとえば、ありうる制約として、スレッド中ではあらゆる変数への書き換えを禁止とし、オブジェクトなどの破壊的なメソッドも完全禁止、とかね。 Erlang ではそのようになっているが、 Ruby や Perl のプログラミングパラダイムとは違いすぎるし、そもそもあまりにも動的な言語なのにどの段階でチェックすれば禁止できるのさってな話になる。簡単な話ではないよ。

Tim Bray の発言についてわたしは ja.reddit で次のように書いた

Erlang の処理系でスレッドが異常に軽量なのはすごいけれど、そうである理由のひとつにあの特異な言語仕様が関わっていると私は思う。 Erlang は非常に制約の強い言語で、スレッドには従来の言語でできたことがかなりいろいろできない(たとえばスレッド間でメモリを共有することはできない)。制限があるために軽量になっているのであり、その制限は Java とかの従来の言語とは適合しづらいんじゃないかと思う。

これは本心でそう思っている。もっとも、だからといってただ諦めるんじゃなくて、うまくバランスを取った処理系がありうるかもしれないので、そこはちょっとだけ期待したいところ。そういう意味では Termite も気になっている。

どうでもいいけど Language::Erlang とか escript ってのは「Perlスクリプトの中に Erlang のプログラム断片がある」ことを想定しているように読めるんだが逆じゃないの。でなけりゃ、あんだけ書いといていったいどんだけあの構文が好きなんだと。