2007-06-04
■ [event][erlang] Erlang勉強会#1
というわけで(どういうわけだ) Erlang勉強会#1 に行ってきた。「参加者はfizzbuzzを書いてくること」という 告知にもかかわらず12人も集まってすげー!と思ったんだけど、 やっぱり半分くらいの人がまだ書けてなかった(笑)。僕ですか?電車の中で頑張って書きましたよ。ええ。
-module(fizzbuzz). -compile(export_all). %これは便利 fizzbuzz(N) when N rem 3 == 0 -> "fizz"; fizzbuzz(N) when N rem 5 == 0 -> "buzz"; fizzbuzz(N) when N rem 15 == 0 -> "fizzbuzz"; fizzbuzz(N) -> integer_to_list(N). run() -> lists:map(fun fizzbuzz/1 , lists:seq(1, 100)). %run2() -> [fizzbuzz(X) || X <- lists:seq(1,100)].
数値を"fizz"とか"buzz"とかに変換する関数を書いて、それを1から100までのリストにmapする方向で実装してみた。
- 定義済みの関数を関数に渡すには fun fizzbuzz/1 のように書く(1は引数の個数)。
- 関数は関数名とarityで区別されるらしい。
最初はlists:seqを知らなくて、iotaという関数を実装してた。
iota(Start, Start) -> [Start]; iota(N, Start) -> iota(N-1, Start) ++ [N].
逆順に作ってreverseするほうが速そうだな。
本編では、練習としてold roman (ローマ数字の簡略版、4をIVじゃなくてIIIIのように書く) を整数に変換する関数を書いた。
-module(roman). -compile(export_all). chr2int($M) -> 1000; % 1文字を整数に変換する。「$M」はC言語の「'M'」、Rubyの「?M」。 chr2int($D) -> 500; chr2int($C) -> 100; chr2int($L) -> 50; chr2int($X) -> 10; chr2int($V) -> 5; chr2int($I) -> 1; chr2int(X) -> erlang:error("invalid char in old roman: " ++ [X]). % ++はリストの連結(format使う方がいいかも)。 old2int(Str) -> Mapped = lists:map(fun chr2int/1, Str), % まず整数のリストに変換して、 Soted = lists:reverse(lists:sort(Mapped)), % ソートしたものを作る if Soted == Mapped -> lists:sum(Mapped); true -> erlang:error("invalid order in old roman: " ++ Str) end.
old romanの仕様から考えると、"VII"はいいけど"IVI"とかはエラーにしたい。ここではまず整数のリストを作って、 それが降順かどうかでエラーチェックするようにしてみた。ソートして同じかを比較するというのはなんきさんの案。 本当は「(apply < ls)」みたいなことがしたかったんだけど(scheme脳)、多引数の「<」みたいな便利なもんはあるのかな。
- erlang:errorでエラーを通知できる。(ここはthrowで例外を投げるほうがいいかも?)
- エラーメッセージは親切にしておかないと、処理系のエラーなのか自前のエラーなのか見分けがつきません(笑) 気をつけよう。
- ifの見た目が変態すぎるw
- ifっていうかcondだよね
- 条件に副作用を持つものは書けない(?)らしい。
その他:
- =:= っていう演算子がある
- ==は、整数と少数を区別しないが、=:= は区別する(1.0 =:= 1は偽)。
- 文字列がなく、数値のリストを作ると文字列と見なされる
1> [104, 111, 103, 101]. "hoge"
- 副作用についてはわりと緩めらしい。HaskellじゃなくてSchemeやOCamlのような。
test() -> io:put_chars("hoge"), io:put_chars("moge"). % 普通にOK
- Emacsのerlang-modeが凄い
- 「;」を打つと、自動的に次の行に関数名を補完してくれたりとか
- 「;」と「.」と「,」を使い分ける→実はエディタ指向言語なのかも
- 例えばC#の仕様はVisual Studioでの補完がやりやすいように考えられてる(という噂)
- HIGHER ORDER PERLという本が熱いらしい
- 目次を見てるだけですでにヤバい(笑)
1558607013
■ [erlang] ESDLが以下略(2)
test\ 以下で
erlc -W -bbeam -I..\.. -I..\include -pa ..\ebin testsprite.erl
とやると、testsprite.beamにコンパイルできる。ってとこまでは分かった。
だがしかし、これを実行しようとすると…
C:\research\Erlang\esdl-0.96.0626\test>erl -pa ..\ebin testsprite.beam Eshell V5.5.4 (abort with ^G) 1> testsprite:go(). Driver Failed {error,driver_incorrect_version} =ERROR REPORT==== 2-Jun-2007::20:23:09 === Error in process <0.29.0> with exit value: {einval,[{erlang,open_port,[{spawn,"s dl_driver"},[binary]]},{sdl,init,1},{testsprite,go,1},{erl_eval,do_apply,5},{she ll,exprs,6},{shell,eval_loop,3}]} ** exited: {einval,[{erlang,open_port,[{spawn,"sdl_driver"},[binary]]}, {sdl,init,1}, {testsprite,go,1}, {erl_eval,do_apply,5}, {shell,exprs,6}, {shell,eval_loop,3}]} **
driver_incorrect_versionって何だよー。
って、driver_incorrect_versionで検索したら自分の日記がでてきた。進歩してねえじゃん。
もうちょっと調べてみる。
■ [ruby][prog] 英語なまりのRuby
Enumerableを操作するのに
@stooges.select {|s| s.name == 'Mo'}
と書く代わりに
@stooges.that.have.name == 'Mo'
と書くためのライブラリ、ho_enumerable.rbについて。
[http://www.rubyist.net/~matz/20070530.html#p04より引用]
一瞬「かっこえー!」と言いそうになったんだけど、プログラミング言語として考えるとこれはセンスないよな。 なんつーか、thatとかhaveが何を返すのかが全然わからんところが嫌だ。せめて
@stooges.that_have.name == 'Mo'
と分けてほしい。
どちらにせよ、自然言語に近くてもプログラミング言語的に不自然だったら駄目だと思う。*1
余談
Lispだと「.」が要らないので、より英語に近くできるらしい。
(例) Loopマクロより:
(loop for x being the hash-keys in ht collect x)
*1 チャレンジとしては面白いけど
■ [ruby] FizzBuzz一般化
14分。
仕様を読み間違えた(optparse使おうとした)のとto_i忘れでちょっとはまった("1".."100" が普通に通るんだよな…)。
require 'enumerator' class FizzBuzz def initialize(argv) raise ArgumentError if argv.size < 2 @start = argv[0].to_i @end = argv[1].to_i @str_mod = [] if argv.size > 2 argv[2..-1].each_slice(2) do |n, str| @str_mod << [n.to_i, str] end end end def run puts (@start..@end).map{|i| s = "" @str_mod.each do |n, str| if i % n == 0 s << str end end s += i.to_s if s.empty? s } end end FizzBuzz.new(ARGV).run
2007-06-05
■ [scheme] FizzBuzz一般化 (2)
動くまでに28分、リファクタリングに10分くらい。
「=」が数値の比較であることを忘れててだいぶはまった。(どの関数のエラーメッセージなのかも出してくれると嬉しいなぁ。)
[D:\proj]d:\prog\Gauche\bin\gosh ./fizzbuzzx.scm 1 100 3 Fizz 5 Buzz *** ERROR: real number required: #f Stack Trace: _______________________________________
回答はこんな感じで。
(use util.list) ;slices (use srfi-1) ;iota (define (fizzbuzz from to mapping) ;mapping -> '((3 . "Fizz") (5 . "Buzz") ..) (define (integer->fizzbuzz i) (let1 mapped (map (lambda (pair) (let ((n (car pair)) (str (cdr pair))) (if (= (modulo i n) 0) str ""))) mapping) (if (every (cut string=? <> "") mapped) (number->string i) (apply string-append mapped)))) (map integer->fizzbuzz (iota to from))) (define (main args) (cond ((< (length args) 2) (print "usage: fizzbuzz.scm 1 100 3 Fizz 5 Buzz ...")) (else (let ((from (string->number (cadr args))) (to (string->number (caddr args))) (mapping (map (lambda (ls) (cons (string->number (car ls)) (cadr ls))) (slices (cdddr args) 2)))) (for-each print (fizzbuzz from to mapping))))))
2007-06-08
■ [ruby] caller_binding
Kernel#local_variables というメソッドがあるだなんて知らなかったよ!(それっぽいのがあるとしたら Binding のメソッドかなあと踏んでそっち探してたよ
[http://yowaken.dip.jp/tdiary/20070608.html#p01より引用]
俺も俺も!あと呼び出し元のbindingを取るのは callcc + set_trace_func でできます(Rails方面ではBinding.of_callerという名前で提供されているらしい)。
■ [web] Re: 「追加して確認」ボタンがなくなった
個人的には「追加して閉じる」ボタンが欲しいです。[あとで読む]でブクマしたあと、手動でウィンドウを閉じるのがめんどい。
2007-06-11
■ [ruby][event] RubyKaigi2007発表者のブログ一覧
日本 Ruby 会議 2007の発表者の方々のブログをまとめてみました。
- (6/13追記:OPMLを作りました。livedoor ReaderなどのRSSリーダに食わすとまとめて登録できます。)
- (6/15追記:version 2になりました。)
一日目
- オープニング (高橋 征義)
- Ruby 1.9実装の現状と今後 (笹田 耕一 ko1)
- 安定版rubyとその今後 (卜部 昌平 mput)
- 日本Rubyのリファレンスマニュアル2007・初夏 (青木 峰郎 aamine)
- JRuby: Ruby for the Java Platform (Charles Nutter / Thomas Enebo)
- 2007年とその先のRuby (まつもと ゆきひろ matz)
- 他言語ライブラリの利用 (立石 孝彰 ttate)
- Cより速いRubyプログラム (桑田 誠 kwatch)*1
- YAR(V)I (Yet Another Ruby (on VM) Implementations) (arton)
- rubyでする Web scrapping - Hpricot と mechanize そして scRubyt (朴 芝印)
- The World In 30 Minutes (Tim Bray)
- Rinda: Answering the RubyConf and RubyKaigi (関 将俊 m_seki)
Lightning Talks
- LT1. 数値データ管理・解析・可視化アプリケーション "Gfdnavi" (西澤 誠也) *2
- LT2. Software is Made of Design and Communication (平鍋 健児)
- LT3. 「Ruby+Miyako」でおもろいプレゼン (サイロス誠)
- LT4. Rubyでファミコンプログラミング (takkaw)
- LT5. Ruby on Railsでデータマイニング (山形 頼之 id:yoriyuki)
- LT6. Rubyのパーサーを拡張して "end" の対応付けをチェックする (山野 ゆき菜)*3
- LT7. マルチコアプロセッサでのRubyプログラムの高速実行方式 (米澤 直記)*4
- LT8. 「地域資源」Rubyと島根県の産業振興の取り組み (野田 哲夫)*5
- LT9. 5分で作るCometチャット (瀧内 元気)
- LT10. データで予想する Ruby のリリース (田中 哲 akr)*6
- LT11. 第2日本Rubyの会について (高橋 征義)
二日目
- もっと仕事で使うRuby (後藤 謙太郎 gotoken)
- JRuby on Rails でエンタープライズ Ruby (高井 直人)
- OpenWFEru, a Ruby workflow engine (John Mettraux)
- AP4R : Ruby のための非同期メッセージングライブラリ (篠原 俊一 id:ita-wasa / 加藤 究 id:kiwamu)
- Inside Ruby/Tk (永井 秀利) *7
- Hello Ruby-GNOME2 World (武藤 昌夫 むとう まさお)
- VisualuRuby計画(仮称)によるWindowsでのGUI開発 (nyasu)
- RubyCocoa - RubyによるMac OS Xソフトウェア開発 (藤本 尚邦 hisa)
- モテる Ruby!Ruby で画像編集のあの手この手 (舘野 祐一 id:secondlife)
- Ruby/SDLとその周辺 (大林 一平 ohai / 原 悠 yhara)
- rcairo (須藤 功平)*8
- 私はいかにRubyでメディア・アート作品をつくり、しかも一円も損をしなかったか (えと こういちろう eto)
- Island Ruby, or How To Survive Invasions, Immigrants, and Cultural Attacks(Dave Thomas)
RejectKaigi
- なぜRject Kaigiが行なわれることになったか勝手に語る (井上 泰之)
- 「ゆきひろ」(not ひろゆき) 認証 (斎藤ただし)
- A Jail development with Rails 2nd edition (竹迫 良範 TAKESAKO)
- MathMLライブラリのご紹介 (黒田 拓)
- オブジェクト指向パーザつくってます。が… (zunda)
- Rel - Ruby (+7NF) (吉田 和弘 moriq)
- Rubyのキャッシュミスをへらす (吉岡 弘隆)
- AgileなRuby教育術 (吉田 裕美 id:yuum3)
- Rubyで作ったゲームデモ (だん dan5)
- fro-grammer (増井 雄一郎 masuidrive)
- My Rspec Best Practice (園田 裕貴 yugui)
- nextとbreakとreturn (田中 哲 akr)
- td2 planet (西山 和広 znz)
- Pragger is LL (松本 宗太郎 soutaro)
- RubycocoaでLimechat (Psychs)
- From Ruby to Java - RoRからEJB3へのポーティング (高井 直人)
- vim (舘野 祐一 id:secondlife)
- High Performance Ruby (ささだ こういち ko1)
- ちょっと私の話を聞いてください (かくたに)
実行委員会
- 高橋征義(日本Rubyの会会長 / 株式会社ツインスパーク)
- 角谷信太郎(日本Rubyの会 || (株)永和システムマネジメント)
- 笹田耕一(日本Rubyの会 / 東京大学大学院情報理工学系研究科創造情報学専攻)
- 重富巧彦(日本Rubyの会)
- のりお(茨城)
- かずひこ(オープンソースプログラマ)
- ただただし(日本Rubyの会)
- 中尾光輝(BioRuby)
- 諸橋恭介((株)永和システムマネジメント/Rails勉強会@東京 裏方)
- 三浦智彦(日本Rubyの会)
- ふしはらかん(日本Rubyの会, 株式会社モバイルファクトリー)
- えとこういちろう(Rubyist, 産総研/東大)
- 荻野淳也(あとで書く)
- 沢田洋平(ニート)
- Zev Blut(TLUG)
- Leonard Chin (日本Rubyの会)
- ながやまん(幹事)
当日スタッフ、ロガー、司会
- たけうち(東京外国語大学)
- 設樂洋爾(dara)
- 島田浩二(snoozer.05)
- 磯辺和彦(株式会社ビジネス・アーキテクツ)
- 柳沢 恵
- 木下史彦((株)永和システムマネジメント)
- だん(日本Rubyの会)
- kitaj(tDiary)
- 斎藤ただし(筑波大学)
- zunda(るびま編集)
- よう(るびま編集)
- すずき みほ (株式会社ツインスパーク)
コメントでいくつかブログを教えていただきました。ありがとうございます。
2007-06-12
■ [Ruby/SDL][idea] 位置決め
ゲーム製作において、キャラクタや文字の位置を決めるのが結構めんどい。「ちょっと座標をいじって再実行」とかさ。
GUIビルダみたいな感じで位置を検討できると便利そうだ。
■ [Ruby/SDL][idea] デバッガ
スライドに書き忘れたんだけどHSPは実行時に変数の内容とか別ウィンドウに表示できて便利だった覚えがあります。
最近local_variablesというメソッドを知ったので、Rubyでも(黒魔術を駆使すれば)実装できそうな予感。
■ [ruby] あるURLからフィードを見つけてくれるライブラリ、FeedDiscover
例のOPMLを作るときにいちいちフィードのURLを探すのが面倒だったので、rubyforgeからそれっぽい (PerlのFeed::Findみたいな)ライブラリを探してみました。
FeedDiscoverを使うと、あるURLのHTMLを解析してフィードのURLを見つけてくれます。
インストールは gem install feed_discover で。
長所
使い方が超簡単なところ。
require 'rubygems' require 'feed_discover' fd = FeedDiscover.new('http://bbc.co.uk/') fd.feeds #=> ["http://newsrss.bbc.co.uk/rss/newsonline_world_edition/front_page/rss.xml"] fd.feed #=> feeds[0]といっしょ fd.feeds? #=> !feeds.empty?といっしょ
短所
- 遅い(パーサのせい?)
- たまにフィードを見つけられない
- たまにHTMLがパースできなくて落ちる
Hpricotベースになるといいなぁ。
■ [ruby][memo] eachで回してるときの次の要素がほしい
ary.each do |item| ... end
みたいな定番のループで、itemの次の要素や前の要素が欲しくなることってないかい?
こういう時はだいたい下のようにインデックスを使うようにするんだけど、もっと簡単な方法はないかな。
(0..ary.size).each do |i| prev = item[i-1] succ = item[i+1] end
隣り合う要素を2つずつ…ってことは隙あらばinjectか?
ary.inject([]){|sum, item| ... }
いやいや、injectは「ある要素」と「そこまでの結果」を扱うメソッドだからあんまり向いてないよな。
prevやsuccが暗黙的に束縛されるようなメソッドを(Rubyレベルで)実装できないだろうか。
ary.each_with_prevsucc do |item| p [prev, item, succ] end
(追記:いろいろな解決案が寄せられています。
- http://mono.kmc.gr.jp/~yhara/d/?date=20070612#c01
- http://mono.kmc.gr.jp/~yhara/d/?date=20070612#c02
- http://mono.kmc.gr.jp/~yhara/d/?date=20070612#c03
- http://d.hatena.ne.jp/odz/20070612
- http://shinh.skr.jp/m/?date=20070613#p01
- http://d.hatena.ne.jp/ku-ma-me/20070613/p2
- http://d.hatena.ne.jp/ku-ma-me/20070614/p1
- http://d.hatena.ne.jp/niha/20070613
- http://d.hatena.ne.jp/ha-tan/20070613/1181759059
- http://d.hatena.ne.jp/sumim/20070614/p1
- http://d.hatena.ne.jp/kaitoh/20070614
- http://d.hatena.ne.jp/xtalco/20070616#1181848684
- http://d.hatena.ne.jp/oto-oto-oto/20070119/1169283285#c
ありがとうございます。あとでまとめるかも。)
■ [ruby] SimpleOPML
RubyでOPMLファイルを生成するクラスを作ってみました。
OPMLはもともと文書のアウトラインを記述するフォーマットとして作られた そうなのですが、今ではなぜかRSSのリストを記述するのに使われているようです。
OPMLファイルの仕様に関しては以下のサイトが参考になります。
require 'cgi' require 'time' require 'kconv' require 'rubygems' require 'hpricot' require 'open-uri' class SimpleOPML Site = Struct.new(:url, :rss, :title) def initialize(title) @title = title @sites = [] end def add(url, rss, title=nil) title = get_title(url) if title.nil? @sites << Site.new(url, rss, title) end def get_title(url) doc = Hpricot(open(url).read) if (title = doc % :title) title.inner_html else "" end end def to_s <<EOD <?xml version="1.0" encoding="utf-8"?> <opml version="1.0"> <head> <title>#{CGI.escapeHTML @title}</title> <dateCreated>#{Time.now.rfc822}</dateCreated> <ownerName /> </head> <body> <outline text="Subscriptions"> #{@sites.map{|s| site_to_outline(s)}} </outline> </body> </opml> EOD end def site_to_outline(site) %!<outline title="#{CGI.escapeHTML site.title.toutf8}" htmlUrl="#{CGI.escapeHTML site.url}" text="#{CGI.escapeHTML site.title.toutf8}" type="rss" xmlUrl="#{CGI.escapeHTML site.rss}" />\n! end end #---- example opml = SimpleOPML.new("RubyKaigi2007 Speakers & Staffs") File.read("sites.txt").each do |line| url, feed = line.split /\t/ opml.add(url, feed) end puts opml
2007-06-13
■ [Ruby/SDL] 「初心者向け」について
ということで、「るびま」で
Ruby/SDLで始めるゲームプログラミング
を見たときには「これだ!」と思ったんですけど、「ウインドウを開く前に変数のなんたるかを知らなければならない」というのは初心者的にはどうなんでしょう(純粋に疑問)。
[http://d.hatena.ne.jp/kmaebashi/20070611より引用]
実を言うとあの記事はもうちょっと初心者向けに書きたかったんですけど、 僕の実力不足で多少Rubyの知識を前提にしています。すいません。*1というのもありつつ。
「Ruby/SDLスターターキット」とMyGameは合体したほうがいいんじゃないかと思うわけですよ。
[http://dgames.jp/dan/?date=20070613#p02より引用]
僕もそうした方が良いような気がしてきましたですよ。- 初心者 → MyGame + スターターキット
- 中級者 → Miyako
- 上級者 → もちろん、フレームワークから自作 :-)
という感じ?
*1 ていうか、本当に初心者向けに書いてたら多分8回連載とかになってたと思われ(笑)
■ [prog] 初心者に特化した言語
あれなんだよな、HSPは初心者に特化した言語だと思うんですよね。 プログラミングに関する前提知識がない人に最適化されてるというか。 僕が触ってた頃(7年くらい前?)はたしか戻り値の概念すら無かったし。
もちろんそれは割り切りであって悪いことではないですが。
Rubyの文法でどこまでその域に迫れるか?ってのも面白いかもな。
■ [softs] タブブラウザfubで蒸発機能が検討されている模様
期待age。
fubはタブをメタタブでグループ化できるブラウザで、さらに終了時に開いてるタブを保存できるので、 使い方によっては開きっぱなしのタブがどんどん増えていく。 だから、これを閉じるなりブクマするなりお気に入りに入れるなりして自分で閉じないといけないんだけど、 自動でなんとかしてくれると嬉しいよね。という話(だと思うけど俺の勘違いかも知れない)。
最後にアクティブにしてから1時間経ったらタブだけ残して中身消しちゃう。
これ欲しい。メモリ消費が少なくなって良さそう。ついでにGMailだけは消さずに置いとくとかできると嬉しい。
2007-06-15
■ [haskell] WindowsでHSDLを使う方法
参考:
- http://d.hatena.ne.jp/TTSY/20070609#p2
- http://www.flightless-wing.com/index.php?%A5%D7%A5%ED%A5%B0%A5%E9%A5%DF%A5%F3%A5%B0%2FHaskell%2FHSDL
セットアップ
- GHC 6.6.xをアンインストールする (ちょw)
- GHC 6.4をインストール
- HSDLを配布ページからダウンロードして解凍
- SDL-devel-1.2.11-VC6.zipをSDLのページからダウンロードして解凍
- HSDL.cabalを以下のような感じで編集
include-dirs: C:/research/HSDL/SDL-1.2.11/include ld-options: -LC:/research/HSDL/SDL-1.2.11/lib
あとは
C:\research\HSDL\HSDL-0.2.0> runhaskell Setup.hs configure C:\research\HSDL\HSDL-0.2.0> runhaskell Setup.hs build C:\research\HSDL\HSDL-0.2.0> runhaskell Setup.hs install
でOK。
テスト
haSDLis(テトリス)をダウンロードして
C:\research\HSDL\haSDLis>ghci main.hs ___ ___ _ / _ \ /\ /\/ __(_) / /_\// /_/ / / | | GHC Interactive, version 6.4, for Haskell 98. / /_\\/ __ / /___| | http://www.haskell.org/ghc/ \____/\/ /_/\____/|_| Type :? for help. Loading package base-1.0 ... linking ... done. Compiling Main ( main.hs, interpreted ) Ok, modules loaded: Main. *Main> main
とするとテトリスが遊べるはずです。
TTSYさんの方法だと、うちではキー入力を受け付けてくれなかったので、 諦めてGHC 6.4を入れてしまいました。
2007-06-20
■ [ruby][event] Ruby勉強会@関西-16「30分でわかるcallccの使い方」
先週末のRuby勉強会@関西で、Rubyにおけるcallccの使い方について発表させていただきました。
継続の説明については「なんでも継続」がよく参照されるんだけど、 ちょっと説明がボトムアップすぎると思うので(僕も最初に読んだときは全然分からなかった)、「callccで何ができるか」という応用面から攻める 構成にしてみました。
最初は「継続かわいいよ継続」「それをすてるなんてとんでもない」と思ってたんだけど、 いろいろ調べてるうちになんでcallccが嫌われるのかが理解できてしまった。callccはかわいいけど、非常に手のかかる奴らしい。 しかも、面白い利用例はいっぱいあるけど実用的な例があんまりないんだよね^^;。
callccが無くなるとRubyの「かっこよさ」が1さがる。そのかわりに「がんじょうさ」が1あがる。さあ、あなたはどちらを望みますか?
以下テキスト版。
要旨
- callccって何?
- RPGのセーブ・ロードみたいに、プログラム中でセーブポイントを作って「そこからやり直し」したりできるものだよ
- callccは凄い!
- 利用例をいくつか紹介します
- callccは危ない!
- プログラムを変なところから「再開」できてしまうので、Ruby本体や拡張ライブラリの実装が面倒になるよ
- Ruby 1.9では、callccの機能の一部を実現する「Fiber」という機能がテストされてるよ
callccって何?
- キーワード:継続、Continuation、callcc
- ドラクエ的に言うと
- 王様と話すとセーブできる
- ドラゴンのこうげき!
- 89のダメージ
- まつもとはしんでしまった
- 王様「まつもとよ、しんでしまうとはふがいない」
- →セーブしたところからやりなおし
- callccはセーブポイントに似ている
- callccでセーブ、cc.callでロード
- callcc{}の返り値:
- cc.call(arg)で飛んできたときはarg
- そうでない時(最初の一回)はブロックの返り値
- まとめ
- セーブ = callcc{|cc| … } # ccがセーブポイント
- ロード = cc.call
- callccの「次の処理」から再開される
callccは凄い!
(1) 3重ループを一発で脱出
callcc{|cc| for i in (0..10) for j in (0..10) for k in (0..10) if i==j && j==k cc.call end end end end }
それcatchでできるよ
catch(:escape){ for i in (0..10) for j in (0..10) for k in (0..10) if i==j && j==k throw :escape end end end end }
google code searchではループ脱出にcallccを使ってる例が 結構あったけど、throw/catchでできるよ
(2) メソッドを「少しずつ」実行する
ゲームのイベント処理
def event king.say(“おお#{@name}よ、しんでしまうとはふがいない”) wait_ok king.say(“そなたにもういちどきかいをあたえよう”) wait_ok king.say(“では ゆけ #{@name}よ!”) end
wait_okをどのように実装すればいい?
def wait_ok loop do input.poll break if input[”ok”] #これは他の処理が sleep 1 #止まってしまうのでダメ end end
普通に書くと非常にめんどう(´・ω・`)
def event(input) case @step when 0 king.say “おお#{@name}! しんでしまうとはふがいない” @step += 1 when 1 @step += 1 if input[“ok”] when 2 king.say “そなたに もういちど きかいを あたえよう” @step += 1 when 3 @step += 1 if input[“ok”] when 4 king.say “では ゆけ #{@name}よ!” end end
callccを使うと…
def event king.say(“おお#{@name}よ、しんでしまうとはふがいない”) wait_ok king.say(“そなたにもういちどきかいをあたえよう”) wait_ok king.say(“では ゆけ #{@name}よ!”) end
- メソッドを「少しずつ」実行できる
- wait_okが呼ばれたたら、セーブしてreturn
- 次回の呼び出しはセーブしたところから再開
(3) 全探索を簡単に
- あるマンションに5人の男が住んでいる
- bakerは5Fではない
- cooperは1Fではない
- millerはcooperより上の階にいる
- smithとfletcherは1つ隣の階にいる…
require "amb" A = Amb.new baker = A.choose(1, 2, 3, 4, 5) cooper = A.choose(1, 2, 3, 4, 5) fletcher = A.choose(1, 2, 3, 4, 5) miller = A.choose(1, 2, 3, 4, 5) smith = A.choose(1, 2, 3, 4, 5) A.assert([baker, cooper, fletcher, miller, smith].uniq.length == 5) A.assert(baker != 5) A.assert(cooper != 1) A.assert(fletcher != 1 && fletcher != 5) A.assert(miller > cooper) A.assert((smith - fletcher).abs != 1) A.assert((fletcher - cooper).abs != 1) p [baker, cooper, fletcher, miller, smith]
- Howではなくwhatを書くだけで解けてしまっている。
- chooseの中でセーブしている
- assertにfalseを渡すと、セーブしたところから値を変えてやり直す
(4) eachを「少しずつ」回す
- C++風のイテレータ
- requrie ‘generator’ (標準添付)
g = Generator.new([1,2,3]) while g.next? p g.next end
(5) ppp
- 変数名も出力してくれるpメソッド
- いちいち p "a=#{a}" みたいに書かなくていいので便利
irb(main):109:0> a = 1 1 irb(main):112:0> ppp :a a = 1
- 実装は超複雑
- Ruby界の3大黒魔術が夢の競演!
- eval系 (eval, *_eval)
- フック系 (*_missing, set_trace_func)
- callcc
- こんなもん誰が考えたんだ
- Binding.of_caller として Rails (ActiveSupport)で導入されたのが初出?
- 1.8.5以降だと動かない…。
callccは危ない!
- なぜ危ない?
- (Rubyの) バグの原因になりやすい
- 油断するとRubyが落ちる
- 例:fooというブロックを取るメソッドがCで実装されていたとする。
foo do puts "hoge" puts "moge" end
static VALUE rb_foo(VALUE ary1) { int *p = malloc(...); … rb_yield(); … free(*p); }
ブロック内でcallccを使うと、rb_yield(); 以下が2回実行されてしまい、メモリを2重開放しようとしてRubyが落ちる。
これを避けるには、Ruby開発陣や拡張ライブラリの作者が常にcallccの存在を気にしてコーディングしなければならない。
まとめ
callccを使うと スパゲッティコードが簡単に書ける!
- callccはとても強力
- 処理の流れを自在に操れる
- でも他人に読めないコードになりやすい
- 見えないところに隠そう
- callccは楽しい
- 思いもよらないことができる
- でもRubyインタプリタのバグ要因になり易い
- 将来無くなるかも
おまけ(Fiberについて)
callccの代表的な使い方は
- (A) 処理の中断/再開 (generator, wait_ok)
- (B) 処理のやり直し (amb, ppp)
の2通りが挙げられる。
callccが危険なのは(B)ができてしまうからだ。 じゃあ(A)の機能だけなら残してもいいかも?ということで、Ruby 1.9ではFiberという機能が検討されている。
FiberはThreadみたいなものだけど、Threadのように自動的に並列実行はされず、Thread#yieldで明示的に移動先を切り替えてやる。 軽量スレッドとも呼ばれるらしい。(Thread=糸、Fiber=繊維)
Fiberを使うと、callccの機能のうち(A)を簡単に実現できる。
Ruby1.9は継続と“Fiber”をサポート - @IT …と書かれてるけど、実際はまだ決まってない。あり得る選択肢は:
- Fiberだけが残る
- callccもFiberも残る
- callccもFiberも残らない
- callccだけが残る
(↑一応、ありそうな順に並べてみた)
- 今後に注目
- 1.9.xは今年のクリスマスにリリース予定です
2007-06-22
■ [ruby] WindowsでRuby-GetText-Packageを使ってみる
Ruby-GetText-Package って?
プログラムの国際化に役立つライブラリgettextのRubyバインディング。「英語の環境では英語で、日本語の環境では日本語でメッセージを表示したい」 みたいな時に役に立つよ。
例えばプログラム中で
print _("Hello World\n") print _("%{filename} is %{filesize} byte") % {:filename => "foo.rb", :filesize => 100}
みたいに書いておくと、実行時に翻訳ファイルと照らし合わせて適切なメッセージに変換してくれる。
他にも単数形と複数形でメッセージを変えたり、いろいろ複雑なことができるみたいだよ。
インストールしてみよう
gem install gettext
で、mswin32 の一番新しい(バージョン番号の大きい)やつを選べばOK。
翻訳ファイルを作ってみよう
基本的に、公式サイトのチュートリアルに従えばOK。
- プログラムを書く(例:hello.rb)。
- 翻訳ファイルのテンプレート(*.pot)を生成する。(rgettext hello.rb -o po/hello.pot)
- 言語ごとの翻訳ファイル(*.po)を作る。(hello.pot を po/ja/hello.po 等にコピー)
- 翻訳する。
- 翻訳ファイルを実際に使うための形式(*.mo)に変換する。(rmsgfmt po/ja/hello.po -o /usr/local/share/locale/ja/LC_MESSAGES/)
非常に簡単です。
翻訳ファイルを使ってみよう
Linuxでは /usr/local/share/locale/ 以下に mo を置くみたいだけど、Windowsではどこに置けばいいのかな。 -d オプション付きでhello.rbを実行してみるよ。
[D:\research\Ruby\gettext]ruby -d hello.rb MO file is not found in d:/prog/ruby/share/locale/ja/LC_MESSAGES/hello.mo d:/prog/ruby/local/share/locale/ja/LC_MESSAGES/hello.mo d:/prog/ruby/lib/ruby/gems/1.8/gems/gettext-1.9.0-mswin32/data/locale/ja/LC_ME SSAGES/hello.mo d:/prog/ruby/lib/ruby/gems/1.8/gems/gettext-1.9.0-mswin32/data/locale/ja/hello .mo d:/prog/ruby/lib/ruby/gems/1.8/gems/gettext-1.9.0-mswin32/locale/ja/hello.mo Hello World
この辺のどこかに ja/hello.mo を置けばいいらしい。 (注:開発中は環境変数GETTEXT_PATHを指定しておくと置き場所を変えられます)
あとは hello.rb を実行すれば日本語でメッセージが表示されるはず…!
[D:\research\Ruby\gettext]ruby -d hello.rb Exception `LoadError' at d:/prog/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_req uire.rb:21 - no such file to load -- gettext Bind the domain 'hello' to 'Object'. Current locale is #<Locale::Object:0x2c8b77 8 @script=nil, @charset="CP1252", @country=nil, @modifier=nil, @language="ja", @ variant=nil, @orig_str="ja"> GetText::TextDomain#load_mo: mo file is d:/prog/ruby/share/locale/ja/LC_MESSAGES /hello.mo Exception `Iconv::IllegalSequence' at d:/prog/ruby/lib/ruby/gems/1.8/gems/gettex t-1.9.0-mswin32/lib/gettext/mo.rb:127 - "\343\201\223\343\202\223\343\201\253\34 3\201\241\343\201\257\344"... @charset = UTF-8 @output_charset = CP1252 msgid = Hello World msgstr = 縺薙s縺ォ縺。縺ッ荳也阜 縺薙s縺ォ縺。縺ッ荳也阜
思いっきり文字化けしとるがな(´・ω・`)
[D:\research\Ruby\gettext]set OUTPUT_CHARSET=Shift_JIS [D:\research\Ruby\gettext]ruby hello.rb こんにちは世界
環境変数を指定しておけばいいらしい。
うーん、「ほとんど全ての環境で設定不要なはずです。」 と書かれてるんだけど、うちのWindows XPは「ほとんど全て」に入らないのかな。
(7/4 追記:コメント欄で環境変数LANGに"ja"等を指定していると文字化けするかも、というコメントを頂きました。LANGを定義しないか、"ja_JP", "ja_JP.SJIS"など正確に指定すれば大丈夫のようです。)
2007-06-26
■ [misc] kitcc
京都工芸繊維大学コンピュータ部におじゃましてきた。
主な目的はリリカルLispを買いに行くことだったんだけど (この距離で通販したら送料と手間がもったいないよね(笑))、KMC以外の「大学のコンピュータサークル」を見るのは 初めてだったので楽しかった。kitccの皆様ありがとうございました。
とりあえず、意外と近かったのにびっくり(一乗寺の天天有の北西あたり…といえば分かる人には分かる)。
KMCとの違い:
- ミーティングは月例らしい (KMCは週2回と妙に多い)
- 部室が学内にある (サークル棟。結構広かった。)
- 部室のデスクトップが少ない (ディスプレイがあったのは2台かな?KMCは6台あるんだが、最近の学生のノーパソ所有率を考えるともう少し減らしてもいいのかも)
- LL系(PerlとかRubyとか)の蔵書がなかった (C/C++が多かったかな。あとJavaとか)
- 部室内に電子部品の在庫がある (KMCはかなりソフトウェア寄りなので…少なくとも去年までは)
- 修士以上はあまり部室に来ないらしい (KMC部員は京都にいる限り引退にならないwので、MとかDな部員がかなり多い)
- 定食屋があまりないので学食が活用される (その代わりラーメンは激戦区!)
- 天天有のおすすめオプションは「煮卵中麺硬めこってりネギ多め」らしい
2007-06-27
■ [ruby] Re:nihaaaaaaaa - split
もしも String#/ がsplitだったら…という話。
s/=/-/
これはキモいw
String#splitに渡すのってたいてい正規表現なんで、「/」が並びまくるという問題はありますな。
words = line / /\t/ words = line / / /
ううむ…。
words = line / (/ /)
括弧つけてもこれはこれでキモいな。
■ [ruby] evalは最後の手段
http://labs.unoh.net/2007/06/railseval.html
うーん、便利だからという理由だけでevalを使うのはあまりおすすめできません。 たとえ自分の足を撃つ危険性を覚悟していても、吹っ飛ぶのが足だけで済まないのがevalなので…。
「文字列からクラスを取得したい」という場合は、Module#const_get というメソッドが使えます。
const_get(name)
モジュールに定義されている name で指定される名前の定数の値を取り出します。定数が定義されていない時には例外 NameError が発生します。 name は Symbol か文字列で指定します。
[http://www.ruby-lang.org/ja/man/?cmd=view;name=Module;em=const_getより引用]
使い方は簡単で、eval k を const_get k に変えるだけでOK(のはず)。
def get_class k = self.class.to_s.gsub(/Test$/, '') const_get k end
evalだと任意のRubyコードが実行できてしまうのに対し、 const_getは定数を取得するだけなので変な入力を与えても(比較的)安心です。
■ [Pragger][memo] PraggerがPlaggerを越えるためには
注) 殴り書きのメモです。
(1) YAMLを捨てる
もしも「初心者にやさしい」という方向を目指すなら、YAMLを捨てて Ruby + DSL に移行すべきだと思う。 インデントベースだとコピペしたら動かなくなった〜とかいろいろありそう。
ただ再利用はYAMLの方が圧倒的に楽。
(2) プラグインの引数に関する(機械可読な)ドキュメントを義務づける
将来Yahoo! PipesみたいなGUIを付けるときに、引数の情報があるのとないのとでだいぶ違うと思う。 プラグインの数が少ない今のうちがチャンスだぜきっと。
(3) フィード以外に活用方法を見つける
Plaggerはフィードを扱うことに特化することでプラグインをうまく組み合わせるようにしてるけど、 Praggerは特に制限がない(っぽい)。 けど現状、フィード以外の便利な用途ってあまり聞かないので、このへんを見つければ面白くなりそう。
というか、公式サイトを見ただけでは
- RubyによるPlaggerの代替を目指すのか
- フィード以外の汎用的なデータを扱う何かにするのか
- 単に作ってみただけで今後のことはあまり考えてないのか
という辺りの「どっちに行きたいのか」が全然分からんので、もうちょっと語ってほしいな。
(4) とりあえずEFT相当の何かが欲しい
ほしいです。てか、作りたいんだけど、Praggerあんまり使ってないからやる気が出なくて、EFT相当の何かができたら使おうと思っている(というデッドロック)。 誰かEFTかやる気かを俺にください。
□ なかもと [お疲れさまです。RubyKaigiには行けなかったけれど、速報ログを見て思ったこと。 →スタータキットで、ゲームだけ..]
□ yhara [提案ありがとう。考えてみます。 Gem Box本にそういうネタがあったと思うので、できるはずだよなぁ。]