トップ 最新 追記

Route 477



2007-06-04

[erlang] もしも「ふつうのErlang」が出版されたら

第1章は「エラーメッセージ」で。

[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))))))

[ruby] Re:もんだい

immutableなはずのFixnumを無理やり変更せよ (or 変更されたように見せかけろ)、という問題。

変数名をiに限定すれば1行で書けますね(笑)。ってのでは駄目だろうな。うーん、どうやるんだろ。Bindingをどうにかするのかな。

pppを思い出したんだけど、pppはシンボルが引数なんで参考にならず。


2007-06-08

[junk] @カプセルホテル

みょーん

[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: 「追加して確認」ボタンがなくなった

個人的には「追加して閉じる」ボタンが欲しいです。[あとで読む]でブクマしたあと、手動でウィンドウを閉じるのがめんどい。

[web] Google Analyticsの登録フォームがアレな件

国名を全部日本語に翻訳してくれてるのは有難いんだが、アルファベット順ソートのままじゃ探しにくくて仕方ないよ^^; (ジャマイカ→日本→ヨルダンって何だ。)

てーか、日本語で表示するならデフォルトで日本を選択してくれといたら良いのに。

[junk] 登録フィードが500を超えた件について

そんなに登録して全部読めるの?と聞かれそうだが

未読が0になるとむしろ不安になります。


2007-06-10

[ruby] どうもyharaです

趣味は睡眠です。

よろしくお願いします。

[ruby][event] RubyKaigi2007\(^o^)/オワタ

良いイベントでした。

本日のツッコミ(全2件) [ツッコミを入れる]

なかもと [お疲れさまです。RubyKaigiには行けなかったけれど、速報ログを見て思ったこと。 →スタータキットで、ゲームだけ..]

yhara [提案ありがとう。考えてみます。 Gem Box本にそういうネタがあったと思うので、できるはずだよなぁ。]


2007-06-11

[ruby][event] RubyKaigi2007発表者のブログ一覧

日本 Ruby 会議 2007の発表者の方々のブログをまとめてみました。

  • (6/13追記:OPMLを作りました。livedoor ReaderなどのRSSリーダに食わすとまとめて登録できます。)
  • (6/15追記:version 2になりました。)

一日目

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

実行委員会

当日スタッフ、ロガー、司会

  • たけうち(東京外国語大学)
  • 設樂洋爾(dara)
  • 島田浩二(snoozer.05)
  • 磯辺和彦(株式会社ビジネス・アーキテクツ)
  • 柳沢 恵
  • 木下史彦((株)永和システムマネジメント)
  • だん(日本Rubyの会)
  • kitaj(tDiary)
  • 斎藤ただし(筑波大学)
  • zunda(るびま編集)
  • よう(るびま編集)
  • すずき みほ (株式会社ツインスパーク)

コメントでいくつかブログを教えていただきました。ありがとうございます。

*1 日記なし?

*2 日記なし?

*3 ただただしさんは代理でPCを設置しただけで、中の人なわけではない模様

*4 日記なし?

*5 日記なし?

*6 IEでは見えないので注意

*7 ページ不明

*8 日記なし?

本日のツッコミ(全13件) [ツッコミを入れる]

Before...

yhara [かくたにさん: アップデートしました。ありがとうございます。]

dan5 [司会がない!]

yhara [鈴木さんファンの方: 追加しておきました(笑)。ありがとうございます。]


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を見つけてくれます。

ドキュメント
http://feed-discover.rubyforge.org/
プロジェクトページ
http://rubyforge.org/projects/feed-discover/

インストールは 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?といっしょ

短所

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

(追記:いろいろな解決案が寄せられています。

ありがとうございます。あとでまとめるかも。)

[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
本日のツッコミ(全3件) [ツッコミを入れる]

ohai [そういうときは zip かな]

nov [そこで Enumerable::Enumerator#{each|enum}_cons ですよ! >> (0..9)..]

takkanm [なんとなく誰も言ってないのは、理由があるのかわかりませんが、each_with_indexで十分じゃないかと思ってお..]


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を使う方法

参考:

セットアップ

  1. GHC 6.6.xをアンインストールする (ちょw)
  2. GHC 6.4をインストール
  3. HSDLを配布ページからダウンロードして解凍
  4. SDL-devel-1.2.11-VC6.zipをSDLのページからダウンロードして解凍
  5. 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]
(4) eachを「少しずつ」回す
  • C++風のイテレータ
  • requrie ‘generator’ (標準添付)
g = Generator.new([1,2,3])
while g.next?
  p g.next
end
(5) ppp
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

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 …と書かれてるけど、実際はまだ決まってない。あり得る選択肢は:

  1. Fiberだけが残る
  2. callccもFiberも残る
  3. callccもFiberも残らない
  4. callccだけが残る

(↑一応、ありそうな順に並べてみた)

  • 今後に注目
    • 1.9.xは今年のクリスマスにリリース予定です

2007-06-21

[web] 日刊スレッドガイド : 至高のシャーペン 究極のシャーペン

Pentel GRAPH1000 FOR PRO はガチ

本当にこれ以外買う気がしないから困る。

[ruby][memo] Dave Thomasのプレゼンより:

  • Rubyは私が考えるのと同じように考える
  • 犬好きと猫好きがいるように、Ruby好きとPython好き、Haskell好きとOCaml好きがいる。そして、RubyとHaskell、PythonとOCamlが好きな人は多いが両方が好きな人はめったにいない

HaskellとOCamlってそういう関係なんすかね。


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。

  1. プログラムを書く(例:hello.rb)。
  2. 翻訳ファイルのテンプレート(*.pot)を生成する。(rgettext hello.rb -o po/hello.pot)
  3. 言語ごとの翻訳ファイル(*.po)を作る。(hello.pot を po/ja/hello.po 等にコピー)
  4. 翻訳する。
  5. 翻訳ファイルを実際に使うための形式(*.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"など正確に指定すれば大丈夫のようです。)

本日のツッコミ(全5件) [ツッコミを入れる]

Before...

yhara [お察しの通り、LANGに"ja"が指定されていました。 LANGを空にするか、"ja_JP"や"ja_JP.SJIS..]

むとう [LANG=jaとしても動作するように修正しました(_JPがなくても大丈夫)。 この変更は次のリリースに含まれます。乞..]

yhara [おお、ありがとうございます。 楽しみにしています。]


2007-06-23

[kmc] OB会

KMCのOB会があった。

最初期の部員の方が「モットーは 年齢 < 知ってる言語の数」とか言ってて衝撃を受けた。


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かやる気かを俺にください。