Archive for May, 2007

ふと思いついたネタ

Posted by on Friday, 25 May, 2007

こんなのふと思いついた。

>

「——織田はハッカーの条件てなんだと思う?」 >

「実装速度か凄いアイディアが出るか ちうハナシか?」 >

「ちがう、もっと……そいつがハッカーになれるかどうかみてえなこと」 >

「……ちゃんとは考えたことない」 >

「オレは、実装の深いところまで深追いできるくらいハックするのが好きなことだと思ってる」 >

「オイ〜〜どっちのがよりスキかーなんちゅう抽象的な理由やないんやろな」 >

「スキってのは集中してるってことなんだよ」 >

「はあ、かもな。で?」 >

「2年目の夏くらいから、かな。三橋ってプログラムのバグが、ナイんだ」

最後だけ急にトンデモないことに。

こうして見ると汎用性の高い台詞まわしだなー


一昨日の話への反論

Posted by on Thursday, 24 May, 2007

えーと一昨日あのように書いたわけですが、まつもとさんがリンクしていた論文に、わたしの書いていることとは違うことが書いてあったので、バランスを取る意味からも紹介したいと思います。

この論文は「スレッドはメモリの共有があるために状態が非決定的になる。したがって人間には予測しづらい」というのを問題点として指摘しています。であれば Erlang のようなものがプログラミング言語の未来だといった結論になってもおかしくありません。しかし、著者は

>

Regrettably, programmers seem to be more guided by syntax than semantics.

と述べた上で、

>

Alternatives that replace these languages with entirely new syntax, such as Erlang or Ada, have not taken root, and probably will not.

と主張しています。「probably will not」てなだけで根拠は上のもの以外に特にないんですが、こう言われてしまうと「そうかもなあ」という気もします。「こんなところで萎えている場合じゃないだろう」っていうのは言いすぎかもしれませんね。

もうひとつ面白いのは次の主張かな。

>

Whereas a general-purpose concurrent language like Erlang or Ada has to include syntax for mundane operations such as arithmetic expressions, a coordination language need not specify anything more than coordination.

つまり、 Erlang のような言語だと、並列プロセスというのは非常にカジュアルに作るというモデルになっています(誰かがどこかで書いていたけれど、オブジェクト指向言語でインスタンスを作るように気軽にプロセスを作る、というように)。これはモデルが違いすぎるので受け入れられづらいんじゃないか、という主張としてわたしは読みました。

そうではなく、並列性以外の部分については通常の言語であるが、並列性についてはきちんと(わかりやすい方式で)利用可能なもの、というのが著者の想定みたいですね。なるほど。

えーと、私のスタンスをここで明らかにしておくと、これから先に Erlang のモデルが主流になるとは思っていません。面白いとは思うけれど、やっぱりもっと穏当な落とし所をみつけた言語が作られて、それが流行ると思う。でも、 Erlang のモデルを知っておくことは個人的には面白いし、知っているといいことがあるような気がするとは思います。

ちなみに Haskell についても同じことを考えています。 Haskell が実用的に使えるかどうかというのは、私個人の興味としてはありますが、それがどうであろうと、 Haskell がそのままのかたちで流行るということはないでしょう。でも、ここで考案された特有な考え方は、便利であれば何らかのかたちでどこかに広まっていくんじゃないでしょうか。そんな風に思っています。

この論文の著者はそういう視点では論じていません。最終的にプログラミング言語はどうあるべきか=みんながメリットを享受できるような主流の言語はどうあるべきかという議論で、そうであればわたしが上で書いた「落とし所」というやつが、この著者と同じことなのかなあ、とは思います(我田引水すぎ?)。ただ、 coordination language というのはわたしはまだよくわかっていません。


ghci のロードって

Posted by on Tuesday, 22 May, 2007

http://madscientist.jp/~ikegami/diary/20070522.html#p01 そういえば、ライブラリを作っていてインストールしたものがロードできなくて悩んだことがあります。

たとえば、こんな感じね。

% ls Data LICENSE Text dist example test HaskellNet Setup.hs _darcs doc haskellnet.cabal % ghci -package HaskellNet ___ ___ _ / _ \ /\ /\/ __(_) / /_\// /_/ / / | | GHC Interactive, version 6.6, for Haskell 98. / /_\\/ __ / /___| | http://www.haskell.org/ghc/ \____/\/ /_/\____/|_| Type :? for help. Loading package base … linking … done. Loading package haskell98 … linking … done. Loading package parsec-2.0 … linking … done. Loading package html-1.0 … linking … done. Loading package network-2.0 … linking … done. Loading package QuickCheck-1.0 … linking … done. Loading package HUnit-1.1 … linking … done. Loading package Crypto-4.0.3 … linking … done. Loading package mtl-1.0 … linking … done. Loading package time-1.0 … linking … done. Loading package HaXml-1.13.2 … linking … done. Loading package HaskellNet-0.2 … linking … done. Prelude> :m HaskellNet.SMTP module main:HaskellNet.SMTP is not loaded Prelude> :l HaskellNet.SMTP [1 of 3] Compiling HaskellNet.Auth ( HaskellNet/Auth.hs, interpreted ) [2 of 3] Compiling HaskellNet.BSStream ( HaskellNet/BSStream.hs, interpreted ) [3 of 3] Compiling HaskellNet.SMTP ( HaskellNet/SMTP.hs, interpreted ) Ok, modules loaded: HaskellNet.SMTP, HaskellNet.BSStream, HaskellNet.Auth.

インストールしたライブラリよりも、ローカルなファイルの方が優先されるというルールなんでしょうね。でもエラーメッセージがさすがに不親切すぎ。はじめてあの「not loaded」ってのを見たときには何が起きたかわからず、かなりビビりました。

(どうでもいい追記)

あれっ、なんで QuickCheck とか HUnit とかをロードしているんだろ?

Crypto が依存しているらしい。おいおい、ライブラリのビルドには必要ないんじゃないのそれ。……build-depends はライブラリとかではなくパッケージのプロパティだから、ライブラリといわず実行ファイルといわず、同じ依存関係になっちゃうのか。うわ、気付いていなかった。なにそれ。


作法の達人はカップ焼きそばをどう食べるか

Posted by on Tuesday, 22 May, 2007

カップ焼きそばを食うたびに掲題のようなことを思うのである。

作法のきちんとしている人は箸先を汚さずに食べるという(少し前にデイリーポータルZでもそういうのがあったなあ)。『美味しんぼ』でも、その件で海原雄山が山岡を叱責するというエピソードがあったりした。ちなみにわたしの箸使いはとても汚い。二十歳過ぎくらいまで握り箸だったし。

でもさ、言わせてもらうけれど、カップ焼きそばをつくってガンガンかき混ぜると、それだけで5センチ以上は箸先が汚れてしまうだろう。食べるまえから勝負がついている恰好ではないか。いったいぜんたい、作法のきちんとした人は、どのように混ぜ、どのようにカップ焼きそばを食べるっていうんだ。

などという難癖を思いながらもしゃもしゃと食うわけだが(昨日は twitter にそんなことをつぶやいてみたりしたが)、さっき革新的な方法を思いついてしまった。

思えば、カップ焼きそばをまぜるときに箸を使う必要なんかない。そこに思考の陥穽があった。菜箸とか、専用の器具を用意して、そういうものでまず混ぜるのだ、行儀よく。

で、まざったら改めて箸で食う。むろん、箸先を汚さぬように。

そうだった。箸でカップ麺をかきまぜるという行為の行儀のわるさにこそ、まずは思い至るべきであったのだ!

などとカップ焼きそばを喰いながら思う初夏の昼。

えーと、オチはありません。


dankogai の Erlang 評に一言いうことにする

Posted by on Tuesday, 22 May, 2007

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 のプログラム断片がある」ことを想定しているように読めるんだが逆じゃないの。でなけりゃ、あんだけ書いといていったいどんだけあの構文が好きなんだと。


カニッツァのピラミッド

Posted by on Sunday, 20 May, 2007

このところ、ときどき science blogs てのを読んでる。といっても記事数が多いので、ぜんぶはとてもじゃないけど読めない。タイトルに目を通すのも1/3くらいかも。で、たまに読むんだけど、今回もその記事。3次元版のカニッツァの三角形というやつ。

カニッツァの三角形は錯視としては有名だから、名前は知らなくても見れば「ああアレね」って思うと思う。アレです。この記事は、その三角形を立体的な背景の上に置いてみました、というものの紹介記事。

背景色が変わっただけなのにちょっと立体的に見えて、ふうん、なるほどね、って思ったんですけれど、これが2007年の「best visual illution of the year」の第二位だったらしい。正確には、これを「動かした」というやつが取ったらしい。そんなコンテストがあることすら知りませんでしたがしかしそんなものかなあ、と思って見てみたんですが(コレね)動くと俄然、立体に見えるもんですね。おもしれえなー。

ところでこれに勝った今年の一位というのはこちら。ただ、こいつの面白さは説明を読まないとちょっとわからないかも。両方とも同じ写真なのだけど、右の方が微妙に傾いて見えるという。ま、それだけの話といえばそうだけど、シンプルなだけに面白い。


電脳コイル(第2話)

Posted by on Saturday, 19 May, 2007

みなさん再放送は見ましたか。今週の第2話も見逃していませんよね。

しかし、まあ、見ていると、作中の「電脳物質」なるものとリアルとの関係はよくわかりません。手で持っているかのように拡張現実をやるには、メガネだけじゃなくて手の位置とかも計測しないといけないんで、けっこうしんどいんですよーとか。あと電脳ペットの計算主体はどこにいるんだとか。ああ見えて完全にユビキタス社会で、電脳ペットは移動エージェントプログラムなんでしょうか。って思うとそれほど驚くべきことではないのか。

ノベライズにも書いてあったし、今週の台詞にもありましたが、実際には触覚を感じないにしては、ずいぶんきちんと持ったり抱えたりしながら活動できるもんだなあというのもねえ。

というあたりは、まあだれでもすぐツッコミ入れられるところではあります。でもまあそれはそれとして「そういうもんだ」と思うことにすると、設定の妙はないにしてもアニメとしては面白いわけで文句はないのだけど。

あといろんな人が言ったり書いたりしているように、たいへんトトロに見える件については絵柄とかキャラ配置もさることながら音楽も一役買っているような気がする。斉藤恒芳ってこんなのだったっけ?

そうそう、上にさらっと書いたけど小説版もあります→電脳コイル 1 (1)

でもねえ、とりあえず読んだんですが、リンクは張っとくけど個人的にはあんまりおすすめしない。つまんなくはないんだけど、基本的にはそんだけというか……このアニメの魅力って、メガネとか、デンスケとか、オヤジみたいなガジェット/キャラの魅力や雰囲気の魅力なんかで、つまり絵面や演出によるところが大きいと思うのだね。あくまでも「別モノ」の小説版っていう触れ込みだからそういう魅力がなくてもいいんだけど、それにかわる魅力を生み出せてはいないなあという感じがした。いや、悪くはないんですけども。


RHGあるいはタブ幅のはなし

Posted by on Saturday, 19 May, 2007

今日は「RHG読書会」。『Rubyist Magazine 出張版』のコラムだけ読むというマニアックな回。案の定、タブ幅とBDDの話で盛り上がり。

タブといえば、 C/C++では、わたしは少し前には、

if (some_condition()) { some_proc1(); some_proc2(); : } else { : }

みたいな風に書いてたんですが、 if の場合、条件の開始と本文の開始が揃っているのがたいへん居心地悪く感じる次第です。いまはコーディングスタイルはこのままにインデント幅は2。

で、肝心のインデント幅については、最近わりとどうでもいいような気がしてきました。で、それはなぜかということを今日、本を読みながらあれこれ考えてきたんですが、字下げの幅って文脈によって変わるからなのかなあと。たとえば lisp だとこんな感じ。

(define (same-circular? l1 l2) (define (check c1 c2) (let loop ((c3 (cdr c1))) (cond ((eq? c2 c3) #t) ((eq? c1 c3) #f) (else (loop (cdr c3)))))) (check (chased-cell l1) (chased-cell l2)))

ま、こんな風に(コードは手元の適当なコードから取ってきたので気にしないように)。基本的な構文の字下げ幅はこの場合2ですが、 cond や if なんかの構造はそうとばかりはいえないし、 let の変数束縛はまたちがったインデントルールを持っていたりとか。

で、この場合には、ハードタブでこういう見た目を表現するのは不可能なのであり、必然的にソフトタブが勝利するのではないか、などとソフトタブ派のわたしは思うのでした。おしまい。

……って思ったんだけど、べつに Lisp とかじゃなくても、メソッド呼び出しの引数を複数行にまたがって書く場合とかでは同じか。

obj.method(argument1, argument2, (cond1)? argument3 : argument4)

みたいに書くときには任意長の字下げ幅を持たないといけない。そういえば、たださんは何かのインタビューで「折り返しはやらない。エディタの幅を広げる方がいい」と主張していた気がするけど(るびまのインタビューだったか)。


Erlang、単一代入と破壊的な変更

Posted by on Friday, 18 May, 2007

昨日の文章を書いてから「ああ、べつに辞書に限った話じゃないからこれじゃ意味ねーな」と遅まきながら気付いたんですが、まあそれはしかたない。その点については
檜山さんから指摘をいただいてしまいました。おっしゃるとおりです。

問題点を抽象的な言葉で書くと、「Erlangは純粋関数型言語で、副作用がない」「しかも更新があった値を同じ変数に格納できない」ということですね。さて、どうするか。

解決策ですが、たとえばループを使うことができます。ループは Erlang では末尾再帰関数を使って書きますが、そうすると自分自身を呼び出すときに違う値を指定すれば、同じ変数に違う値を束縛できる。いわば、引数を状態変数として考え、自分自身を呼び出すのを更新とするわけです。

でも、世の中そんなにループばっかりじゃない。ここでやりたいのは普通の逐次的なプログラムを書くことでした。そこで「状態をもつループ」をほかのプロセスへと切り離してしまいます。メッセージを送るとその時点での状態を参照し、メッセージに従って値を返したり、更新したりできます。

では、コードを示します。

-module(dsets). -compile(export_all). new() -> spawn(?MODULE, loop, [gb_sets:empty()]). loop(Set) -> receive {From, {add_element, V}} -> From ! {self(), ok}, loop(gb_sets:add_element(V, Set)); {From, {del_element, V}} -> From ! {self(), ok}, loop(gb_sets:del_element(V, Set)); {From, {is_element, V}} -> From ! {self(), gb_sets:is_element(V, Set)}, loop(Set); {From, is_empty} -> From ! {self(), gb_sets:is_empty(Set)}, loop(Set); {From, size} -> From ! {self(), gb_sets:size(Set)}, loop(Set); {From, get_set} -> From ! {self(), Set}, loop(Set) end. rpc(Pid, Msg) -> Pid ! {self(), Msg}, receive {Pid, V} -> V end. add(Set, V) -> rpc(Set, {add_element, V}). del(Set, V) -> rpc(Set, {del_element, V}). elem(Set, V) -> rpc(Set, {is_element, V}). is_empty(Set) -> rpc(Set, is_empty). set_size(Set) -> rpc(Set, size). get_set(Set) -> rpc(Set, get_set).

シェルで実行させてみました。

Erlang (BEAM) emulator version 5.5.4 [source] [async-threads:0] [kernel-poll:false] Eshell V5.5.4 (abort with ^G) 1> c("/Users/mukai/erlang/dsets", [{outdir, "/Users/mukai/erlang/"}]). {ok,dsets} 2> Set = dsets:new(). <0.39.0> 3> dsets:is_empty(Set). true 4> dsets:add(Set, "jmuk"). ok 5> dsets:add(Set, "m-hiyama"). ok 6> dsets:elem(Set, "jmuk"). true 7> dsets:del(Set, "jmuk"). ok 8> dsets:elem(Set, "jmuk"). false

こんな具合でうまく行っています。

Erlang ではこういうモノを書くことはそれほど珍しいことではありません。 digraph がどうなっているか、ソースコードは見ていないのでわかりませんが、ごく簡単にはこんな風に実現できます、という例として読んでください。

さて、反論はいくつか思いつきます。第一に、非常にメンドくさい。いちいちこんなことを書いてられっか、という話があります。現実問題としては、こういうことをラップしてくれるライブラリがあると嬉しいんですが、あるんでしょうか。エラソーなことを書いていますがわたしも Erlang 初心者ですから、実はよくわかっていません。もっとも、これを実現する簡単かつラクな API ってちょっと思いつきませんけれど。

それからもうひとつ。このプログラムはガベコレの観点からの問題があります。ふつうの gb_sets は、参照するものがいなくなったら自動的に消滅することが期待できますが、これはプロセスなので簡単には止まりません。どうするか。

簡単な対処方法はあります。 Erlang のプロセスには「リンク」という機能があり、リンクで繋がったプロセス同士では、一方の終了をもう一方が検知したりできるようになっています。これを使い、接続してきたプロセスを覚えておいて、接続したプロセスがみんな終了したら自分も終了する、といった方法です(あとで参照しなくなる永続プロセスがいたらアウトだけど……)。

ところで、ほかの関数型言語では、どうなっているんでしょうか。たとえば Haskell では、同じように関数的な Data.Set というものがありますが、これはどうでしょうか。ただ、 Haskell や Lisp や ML の let 束縛では、過去に同じ名前の束縛があっても隠蔽してくれます。つまり、

import Data.Set as S ... let s = S.empty in let s = S.insert "jmuk" s in let s = S.insert "m-hiyama" s in ...

などと書ける、かというと実は Haskell は特殊事情があって書けませんが(笑)、 Lisp や ML なら書けます。でもね、こんな風に書くのはシロウトですよ。じゃあクロウトはどう書くんですか、というと、これはjijixiさんが書いてくれているので略させていただきます。

この fold は ugly に見えます。でもまあ、実際には処理が定型ならラップする手段があります(たとえば from_list のような関数がたいていは定義されています)。こんな風にやるのが「関数型言語風」なんです。

まとめ。

>
  • Erlang では副作用のある処理をプロセスを使って表現する(じつは io なんかも内部的には「入出力プロセス」へのメッセージとして表現されています) >
  • 関数型言語のパラダイムでは、コレクションタイプに逐次的にデータを入出力するようなことは違った風に書くため、単一代入でも実は問題になることはめったにない

  • Erlang、単一代入と辞書

    Posted by on Thursday, 17 May, 2007

    http://d.hatena.ne.jp/m-hiyama/20070517/1179360670ありうる不満ですが、たぶん次のようにして解決できるんじゃないかと思います。

    まず、実は Erlang のどんなプロセスも辞書を最初っから1つずつ持たされて生まれてきます。そして、その辞書へは put と get という2つの組み込み関数によって操作ができます(cf. http://www.erlang.org/doc/doc-5.5.4/doc/reference_manual/processes.html#10.9)。

    ですから、

    sample() -> D0 = dict:new(), D1 = dict:store("板東トン吉", [27, male], D0), D2 = dict:store("大垣ペケ子", [21, female], D1), Val = dict:find("板東トン吉", D2), Val.

    これは、

    sample() -> put("板東トン吉", [27, male]), % 項目を格納 put("大垣ペケ子", [21, female]), % さらに項目を格納 Val = get("板東トン吉"), % キーに対する値を検索し Val. % それを返す

    このようにして書けるのでした。いーでしょ。……だめ?

    「そんなこといったってプロセスに2つの辞書が欲しくなったらどーすんだYO!」ってお思いのあなた。あなたはすでに既存言語の呪縛に囚われている。そういうときはプロセスを分ければいーじゃないですか。

    まあ、いびつな解決策だと思いますけどね(笑)。

    >

    洗練されてパーフェクトなものより、少し奇妙で不格好なほうが魅力的だってことがあるでしょ。そういう魅力があるね、Erlang。

    わたしもそう思います。

    本題と関係ないけど檜山さんのところは「キマイラ飼育記」だと思ってました。すいません。