第23回 コンピュータシステム・シンポジウム (ComSys 2011) に来ています.うちの専攻の学生さんが論文賞をとっていて素晴らしい.
うちの研究室の学生さんがポスター賞を受賞した.素晴らしい.
http://blog.tatsuru.com/2011/11/24_2042.php
「学び」というのは、なんだか分からないけど、この人についていったら「自分がほんとうにやりたいこと」に行き当たりそうな気がするという直感に従うというかたちでしか始まらない。
難しい.
自分を振り返ると,「面白そう」という言葉でしか表現できないんだが.
成長する前に「僕はこれこれこういうプロセスを踏んで、これだけ成長しようと思います」という子供がいたら、その子には成長するチャンスがない。というのは、「成長する」ということは、それまで自分が知らなかった度量衡で自分のしたことの意味や価値を考量し、それまで自分が知らなかったロジックで自分の行動を説明することができるようになるということだからです。だから、あらかじめ、「僕はこんなふうに成長する予定です」というようなことは言えるはずがない。学びというのはつねにそういうふうに、未来に向けて身を投じる勇気を要する営みなんです。
修論の落としどころを学生さんが考えてるとそこまでしかできない,ってところか?
子供たちを閉じ込めて、閉鎖集団の内部で相対的な優劣をつけて、相対的優者に報酬を、劣者に罰を与えるということをしたら何が起こるか。集団全体の学力が下がるだけなんです。必ず下がる。なぜかというと、閉じられた集団の中の相対的な優劣を競うのであれば、自分の学力を上げることと、まわりの学力を下げることは「同じこと」だからです。そして、自分の学力を上げるのと、まわりの子供たちの学力を下げるのでは、後の方が圧倒的に費用対効果が高い。だから、子供たちを競争的環境に追い込めば、子供たちは互いに争って、となりの子供たちの学習意欲を失わせようとする。必ずそうなる。
衝撃的だ.
考えさせられる話だった.
面白い,カッコイイ,がモチベーションになる大学院ってのは,とても恵まれた学びの場だなぁ.
そこにはきっと,信頼感とかが大事なんだと思う.
コミュニケーション力向上に役立ったOSS活動 - Linux/Ruby 小崎資広氏
「しがらみなどが原因で作業時間が確保できない」というのであれば、環境を変えるなど、対策はいくらでもとれると思いますが、
※ただしイケメン(略)
まつもとさんが matz メソッドが欲しいと twitter で呟いていたような気がしたので考えてみました.
ただ,まつもとさんは 2.0 が 100% compatible と仰っていたので,メソッド追加なんてできません.そこで,matz メソッドのときだけ「名前が悪い」と NameError を吐くパッチを書いてみました.
利用例:
$ ./miniruby -e 'matz' -e:1:in `<main>': unsuitable local variable or method name `matz' for main:Object (NameError)
パッチ:
Index: vm_eval.c =================================================================== --- vm_eval.c (revision 33771) +++ vm_eval.c (working copy) @@ -545,7 +545,12 @@ format = "protected method `%s' called for %s"; } else if (last_call_status & NOEX_VCALL) { - format = "undefined local variable or method `%s' for %s"; + if (id == rb_intern("matz")) { + format = "unsuitable local variable or method name `%s' for %s"; + } + else { + format = "undefined local variable or method `%s' for %s"; + } exc = rb_eNameError; } else if (last_call_status & NOEX_SUPER) {
もちろん,エラーメッセージが変わってしまうので 100% compatible にはできていないのですが,メソッドを追加するよりはマシかなぁ,と.
すわ,JOKE カテゴリを使うときか! と思ったけど,日和って日記に書きました.
マルチコア時代のサーバプログラミングとHaskell 大変興味深い資料なんですが,Ruby であんまり性能が出ていないので,エコーサーバをとにかく速くするようなチャレンジをしてみたいんですが,他の言語とかのサンプルコードはどっかに公開されていないものか.
Ruby はこんなコードも通ってしまうから凄いですね。
# ふつうにヒアドキュメントを書いた場合 def foo puts <<-__EOS__ foo1 __EOS__ end # end の後にヒアドキュメントが続く場合 def bar; puts <<__EOS__; puts <<__EOS__; end bar1 __EOS__ bar2 __EOS__ foo bar
つまり、メソッド定義の "end" の位置以降に、その定義に必要な要素が含まれている、という。
iPhone 4S を買ったので、こまめに家計簿、というか出費歴をとるようにしてみた。11月は、もう3万円使っていることがわかる。なんという浪費。
というわけで、一食500円ですませるようにしようとしてるんだけど、500円はなかなか厳しいものがありますね。どうしてもファーストフードによってしまう。
積極的に自炊をするしかないか。
実は,外食よりも,飲み会のほうが金使ってるんだよな.一回6000円で2回飲んだだけでもう1.2万円(一月の予算の 1/5).
ドワンゴさんで就活のために見学させてもらってきました.@coji さんありがとうございました.
ニコニコ動画のこと,よく知らなかったんですが,色々教えてもらいました.楽しかった.
NDA 結んでたので,中で見たこと聞いたことは話せないようなのだけど,「Ruby は遅いから使えない」と言われたというのも NDA の中のことだから内緒にしておこう.
学生さんの就活のためにね.
バイトコード書き換えができるべきか,最近ずっと考えているんだけど.個人的には反対なのだけれど,そう思わない人も多いようなのですよねぇ.
昨日の松田さんのインタビューは大変面白かったので,早くリリースされるといいなぁ.
http://wota.jp/ac/?date=20100426 ででぃすられてるし,1行でメソッド定義を書ける文法が欲しい.と,前から考えているわけですが.
def add1 x; x+1 end # 今でも動くが ; とか end とかうざい x+1 def add1(x) # 後置の if def add1 x -> x+1 # sora 案
sora 案は,なかなか悪くないように見える.が,ブロックの構文(-> x {x+1})と合わないんだよなぁ.-> x {x+1} 自体,ちょっとアレだなぁ,と思わなくもないんだが,もう入ってしまっているので覆せないというか.
def add1 -> x {x+1}
は嫌だ.
同じネタで日記を書いた記憶があるんだけど,もう覚えていないという.
def add x := x + 1 #sora案の類似だけどこっちのがいいなー
foo!! メソッドを許すと何が嬉しいのか.
def けいおん!! p:けいおん!! end def Working!! p:Working!! end けいおん!! Working!!
が半角で書ける.
foo!? を許すと何が嬉しいか.
http://twitter.com/#!/igrep/status/133823718634954752
RubyのSet# add?みたいに副作用があってかつ述語のように使われるメソッドに使うならありかもしれませんね。
とても真面目な答えを頂きました.
foo!! とか foo!? が許されると,なんか新しいコンベンションを足すことができるかなぁ,と.
foo!!!!!!!!!!! とか許す?
foo???? とか.
scheme ならこんな苦労はないのに.
ベーコンエッグを半熟じゃないようなので作るにはどうしたものか.
やはり,topic ごとに何か書くには,ブログなるもののほうが良さそうだなぁ.うーん.
最近,自分の柔軟性がなくなっているのに危機感を覚えている. 前からそういうところあったけど,とくに.弾力性というか.
カリスマ安藤さんの [ruby-core:40806] [ruby-trunk - Feature #5583][Open] Optionally typing というご提案.
optional 引数については,何度も提案がありましたが,あまりまとまってない話の1つと言えると思います.
で,いくつか穴を指摘してみると,
というのが,ぱっと思いつきます.
1 に関しては,foo(str@String) とかするといいでしょうか.
2 に関しては,String もしくは nil,と nil は暗黙の内に仮定されている,とするのがいいでしょうか.
3 に関しては,例えば foo(str@{to_str}) とか,foo(ary@{each, []} やっておいて,to_str メソッド,もしくは each,[] メソッドを持つもの,とかするといいでしょうかね.
で,できることと言えば,型チェックをするコードを強制的に挿入する,とかでしょうか.テストコード書くより楽,と.最適化はどうなんだろうなぁ.
この辺は,変数とかメソッドに属性を与える文法(str@Stringみたいに,var@attr とする文法)とかがあって,それを展開して云々,とかできるといいでしょうか.
今,学生さんがとても面白い研究をしているのだけど(うちの学生さんは皆さん面白い研究をしているのだが),その1つに dRuby の拡張みたいなことをしている人がいる.
例えば,dobj が分散オブジェクトだとして,
ary = [] a << dobj.foo a << dobj.bar a << dobj.baz p a
こうしたときに,dRuby なら毎回 foo,bar,baz メソッドを毎回遠隔メソッド呼び出し(RMI)するわけですが,実は p a というメソッドを実行するまで,結果は不要なわけです.ということで,p a(されたときに呼ばれる inspect)が来るまで RMI を遅延し,メソッド呼び出しをされた時点で foo,bar,baz メソッドを呼んでやってもよいわけです(foo で例外が出たら...,とか考えるとアレですが).
メソッドが呼ばれたときに遅延されていたメソッドを一気に実行する,ってのはありそうですが,例えば a[0] がまだ実際には計算されていない時に,
if a[0] ... end
なんてコードを実行すると,a[0] には遅延実行するための proxy オブジェクトが入っていたりして,RMI の結果は nil だったりするんだけど proxy オブジェクトは条件文では真になるため,このコードは通ってしまう,とかはありそうな問題です.
そこで,
if a[0].nil? ...
このように nil? メソッドを呼んでやると,期待通りの動作になります.が,Ruby っぽくないわけです(nil? なんて書いたことがありますか?).
さて,こういうのはどうしたものか?
とか,こういう話は分散オブジェクトとか,そういう研究で嫌というほど出ているような気がするんだけど,さて関連研究ではどうしているんだろうか?
そういえば,真か偽かを返すメソッドって無いな.true? / false? とすると,true / false なのか,真か偽か,とわからないという.
ちなみに,Ruby では false と nil が偽.
そこは遅延実行を透過にするのが言語としては一番綺麗 (値を参照しようとしたらforce、つまりimplicit forceみたいなの)かなあという気が個人的にはします。実装上、後付けでそれを入れるのは色々面倒ですが。
実用上は同期点を明示してやっても十分使えると思いますが (p aやa[0]の前に syncメソッドを読んでやるとそこで結果待ち合わせ、とか)、それだと研究にはなりませんしねえ。
はい,綺麗なのは同意.同期点の明示,は十分使い物になる,のかなぁ.自信が無い.先日書いたDSLの話で何とかなりそうな気もしているのだけど.
メソッドを複数まとめて送るって高速化は,すぐに文献が見つかると思ったけど見つけられない.うーん.
バッファリングするやつは基本的には返り値を期待しない「コマンド」で、返り値を期待する/syncする部分で待つっていうのが、まあ普通ですよね。
返り値を期待するところでpromiseかfutureを返しておいて、実際にその値が使われるところでforceするってのはありそうなんですが、"promise"とか"future"とかめっさ検索しにくい単語ですな。とりあえず J Schwinghammer, A concurrent λ-calculus with promises and futures
のp14にfuture使って「記述は同期的だけど実は非同期なRPC」をやる例が出てました。
Multilisp関連の論文、例えば 「Speculative computation in multilisp」はどうでしょうか?
反応してもらえて嬉しいです。
ご指摘の穴についてですが
1. むしろキーワード引数の方を := にするというのを考えました。 def foo(bar : String := 'default') みたいな。記法としてはわりと美しい気がします
2. nilは暗黙的に認める方向で
3. duck typingに関してはいちいち羅列するよりも、諦めてメッセージの集合としての interface を宣言できるようにした方が幸せかもしれません。 interface Arrayish; @each; @[] end みたいな。で、後は普通に foo(ary : Arrayish)
nilを認めるってことは、NilClassが全ての型のsubtypeになるとも言えるので型的にはちょいと気持ち悪いですね (まあJavaとかありますが)。
でもduck typer的に、「型とは、特定のメソッド群に返事を返すものである」とするなら、「どんなメソッドにも返事を返すもの」は全ての型のsubtypeになれるので、例えばnilはnil? 以外にはどんなメソッド呼ばれてもnilを返す、とかしてしまえば型的には落ち着くのかな。
そうしたらあらゆる計算がMaybeモナドを通す感じになって、計算の途中でnilが出てきたら結果はとにかくnilになる、って感じになって、それはそれで一貫しているような。使い辛そうだけれど。
NilClassはScalaがなんかいい感じに処理してた気がします。どういう扱いだったか覚えてないですが・・・
ScalaではおっしゃるとおりNothingが全ての型のsubtypeになるみたいでした
そうなんですが、そういうbottomな型って値を持たせないことが多いような。ScalaのNothingも値は無いですよね。あーでもScalaには(全ての参照型のsubtypeになる)Nullがあるのか.ややこしいな。
eval と binding を監視して,もし alias されたら元に戻す,という話を考えてみたところ,やはり 100% compatible を考えるとどうにもならない話の証左.
def foo alias hoge eval end def bar i = 1 foo p hoge("i") end bar
foo() の途中で hoge という eval の alias を作っちゃう.なので,「あ,eval() ないし,i はもう使わないから消しちゃっても大丈夫」と判断して i を消した後で,実はやっぱり i が必要でしたー,ってときに,対処のしようがないという.
まぁ,あと Proc#binding という奴もいるから,ブロックがあると use になっちゃうってのもあるなぁ.これは headius に散々根に持たれている(1.9 に俺が入れたから).
先日,プログラミング研究会というところで「Ruby 用マルチ仮想マシンによる並列処理の実現」という発表をしてきました.http://atdot.net/~ko1/activities/ に資料があります.
さて,どうしたものかなぁ.2.0 には入らないにしても.うーん.
かれこれ数年研究者をやっているが,やはり論文リストが少ないなぁ.うーん.やはり研究者に向いていない.
業績リストが厚い(長い)のは,ひとえに優秀な学生さんのおかげ.いや,マジでうちの学生さんは凄いと思う.というわけで,企業の人は釣りにくるといいと思うよ.
def foo i = 'foo' p eval('i') end
こういうコードを ruby -w で実行すると,警告が出ます.
t.rb:2: warning: assigned but unused variable - i
eval の中で使ってるんだけど,コンパイル時にはそんなことわからないため,i が使われないんじゃないの,って警告しています.わかっちゃいるんですが,鬱陶しいです.
例えば,i.__id__ なんて意味のないコードを入れると,警告が抑制できます.ただ,ちょっと鬱陶しい気もします.どうにかなんないでしょうか.
eval() なんて使う奴が悪い,といえばそうなのかもしれないので,では eval で使える変数こそ,何か宣言させるというのはどうでしょうか.
def foo i = 'foo' # @eval_var(i) p eval('i') end
@eval_var(i) とすると,この i は eval から使える,という意味ということにしておきましょう.そうしない変数は eval から使えないようにします.こういう仕様にすると,VM 開発者は泣いて喜びます.多分.
でも,2.0 は 100% compatible らしいので,無理だろうなあ.
DSL の話とか FeatureSpace の話とか(shiroさん以外)絡んでくれなくて寂しい.
JavaScript とかだとそういう制限は use strict すると発動、とかしてますね
そういうeval (ローカル環境を掴むeval) を許すなら、evalの呼び出し自体がそこから見えるスコープの変数を全て利用しているとも考えられるので、むしろ警告の方がおかしいと考えることもできますね。
ところで他のメソッド経由でeval呼んだ場合ってスコープはどうなるんでしょうか。
def foo i = 'foo' p bar('i') end def bar(s) eval(s) end
このevalからiが見えないのであれば、evalだけ特別扱い (eval呼び出しから可視の変数は全て使われてるものとする) でも良いような。
一方iが見えるのであれば、それはダイナミックスコープってことなので静的解析とは相性最悪ですねえ。
前者(bar から i は見えない)です.問題は,eval が eval であることをコンパイル時に解析できないことです.つまり,eval はメソッドなので,alias される(別の名前である)可能性があります.そのため,Ruby コミュニティには eval はキーワードであるべき(静的解析できるべき),という意見があります(とくに実装者に).
というか,この環境の binding (環境)を取り出す,ということをコンパイル時に解析できるようになっていると良いのですが.
で,案としては
とするというのもあります.つまり,
def foo i = 1 eval('i') end
はエラーで,
def foo i = 1 eval('i', binding) end
は ok,ただし binding キーワードが見えるので,このメソッドの変数 i (とか)は無限 extent を持つことがわかる.
これが許されると lambda lifting とかできていいのですよねぇ.コンパイラの夢が膨らみます.
ただ,100% compatible という言葉が,やはり色々阻害します.
eval もしくは binding の alias をひたすら監視して,もし発生したら deoptimize する,とするか? しかし,この deoptimize は元に戻れないのがなぁ.
ふむ。call/ccが手続きの癖に暗黙に実行系内部の情報を掴むのと問題としては似てますね。Schemeではスコーピングが静的であることがそもそもの原点なので、ローカル環境を掴む手続きというのは(ちらほら提案されてはいるけど)規格の議論には上らなさそう。
Ruby で DSL を作る方法はいくつかある.DSL とは,用途に応じて言語をカスタマイズしよう,とか,そんな感じ.いや,違う気がするなぁ.まぁいいや.
で,その DSL の実現方法をまとめてみた.
■1) メソッドを定義する
rake なんかがそうなんだけど,一見 Ruby のコードっぽく見えて,普通に Ruby のプログラムとして動く.普通の Ruby プログラミング.
■2) method_missing で頑張る
Ruby のプログラムとして動くんだけど,定義されていないメソッド名に応じて何か処理をする. ActiveRecord とかは,多分そんなんじゃないかと思う.
■3) メソッド呼び出し情報をためる
1, 2 の延長だけど,メソッド呼び出し履歴をためておいて,その履歴を用いて構文木っぽいものを作り,その情報を用いて何か別の挙動をする.
ここまでは,Ruby プログラミングテクニックって感じ?
■4) parse-tree を使う
メソッドとかから,抽象構文木を取り出してなんかする.1.9 では使えない.
■5) ripper を使う
1.9 では,Ruby のプログラム文字列を抽象構文木に変換する Ripper というライブラリが入っているので,それを使って parse-tree 的なことができる.ただ,メソッドなどからプログラムの文字列を取り出す手段が今はないので,このメソッドの構文木,みたいなことができない.
■6) 自分で ruby のパーサを書いて,別のことをさせる
Ruby っぽい文法が使える(学習コストの削減),という意味はあるが, もう,Ruby である意味はあんまりない.
他にもあるかな? あったら教えて下さい.
で,Ruby の文法自体が柔軟(?)なので,(1), (2) あたりでだいたいのことができちゃうよね−,っていうことで Ruby の DSL が大人気(rake とか)だったりするわけです.
で,実際はメソッド呼び出しじゃなくて,例えば同じ挙動をする C のコードに変換したい,とかあっても,(3) の方法を使えばプログラムの挙動を結構簡単に取り出すことができます.
例:
class Emitter < BasicObject def initialize @seq = [] end undef == undef ! def method_missing(*args) @seq << args self end def to_a @seq end end e = Emitter.new e.search(:foo) e + 1 e / 2 e != 3 !e p e.to_a #=> [[:search, :foo], [:+, 1], [:/, 2], [:==, 3], [:!]]
こんな感じで,実際に何が呼ばれたかわかるわけです.== とか != とか ! とかも取れているのがポイントですね.すべてのメソッドを method_missing でひっかけるために,undef !, == して,BasicObject を使っています.
search をもうちょっと頑張ると,
e.search(where: 'foo').sort_by(:date) p e.to_a #=> [[:search, {:where=>"foo"}], [:sort_by, :date]]
こんな感じの配列が取れます.こんなのは,SQL に変換するのは簡単ですね(多分.私はよく知らない).
ただ,ここに if 文とか and とか or という Ruby の文法要素についても取り出そうとすると,if や and や or はメソッドではないので method_missing(や他のメソッド呼び出し)でひかっけることができません.
この辺をやろうとすると,例えば
e.if(cond, ->{then}, ->{else}) e.and(a, b)
みたいに,無理矢理メソッドにしてしまうという方法(3 の延長)があります.SQL の where に使うにはこんな感じにするんでしょうか.
query.select(table).where(e.and(:size > 10, :price > 500))
ただ,この方法は,Ruby プログラムっぽくないから美しくありません.if は普通に if 文で書きたいわけです.
そこで,(4) や (5) の手法がとられるわけです.とくに,parse-tree は Ruby プログラムを実行中に,定義されたメソッドなどの情報が取れるわけで,非常に柔軟な変換が可能になるわけです.
ただ,(3) と (4) では,実は難易度に断絶があります.(3) までは,純粋に Ruby の知識があればなんとでもなる話でした.しかし,(4),(5) は Ruby の文法の細かい知識,というか,抽象構文木の設計を知らなければなりません.(6) は知らなくてもいいかもしれないけど,まぁそれ以上に大変でしょう.
というわけで,(3) と (4) の間にくるような方法を思いついたという話でした.それはまた今度.
ちなみに,macro のある言語ではこういう心配は要らない.Python とかは,そもそも DSL に向かないんじゃないか?(知らないけど).Perl とかはどうなんだろ.
機能の FeatureSpace はいくつか機能を分割できそうな気がしてきた.
実装的には,最後のリテラルが問題だよな.immediate 問題.
cfunc の dispatch を速くするアイデアを思いついた.具体的には,optional 引数をとるようなメソッドで,それを毎回 callee がチェックしているのをなんとかする話.
別のFeatureSpaceで作られた、名目上同じクラス(e.g. String)のインスタンスって、実行時には別のクラスに属するものになるんでしょうか。そういう方針みたいな感じですが。
実は同じクラスで、それが持ち込まれるFeatureSpaceによって振る舞いが変わるっていうのもありかとちょっと思ったけれど (そしたらリテラルが属する実質のクラスをリテラル生成時に決めとかないでも済む)、それを許すとあるFeatureSpaceではインスタンスの状態に一定の制約をかけているのに別のFeatureSpaceではそれと矛盾する変更を許してたりしてオブジェクトを行ったり来たりさせると面倒なことになるかなあ。
全部immutableにすれば面倒は減るぞきっと。関数型万歳。
はい,複数のオブジェクトが同時に利用できるようになる感じです.異なるバージョンの複数のライブラリを共存,とか考えていました.immutable は今回関係あるかなぁ.
これとか? http://jan2012.ml-class.org/
ざっとどんなものなのかをみたいならこの資料はサッと読めてオススメです。 http://www-tsujii.is.s.u-tokyo.ac.jp/~hillbig/papers/2008-08-03-crf.pdf
日本語で読める本だと、私が知る限りでは言語処理のための機械学習入門が一番のオススメです。が、違う分野をやってる人だとまた違うオススメがありそう。 http://www.coronasha.co.jp/np/isbn/9784339027518/