今日のLLVM - フィボナッチ数列

投稿者 nanki 2009-12-25 10:35:00 GMT

LLVM言語にて、フィボナッチ数列。

@str = internal constant [4 x i8] c"%d\0A\00"

define void @main() nounwind {
init:
  br label %loop
loop:
  %i = phi i32 [0, %init], [%i.next, %loop]
  %fib = call i32 @fib(i32 %i)

  call i32 (i8*, ...) @printf( i8* getelementptr ([4 x i8]* @str, i32 0,i32 0), i32 %fib)

  %i.next = add i32 %i, 1

  %cond = icmp ult i32 %i.next, 30
  br i1 %cond, label %loop, label %exit

exit:
  ret void
}

define i32 @fib(i32 %n) nounwind {
  %cond = icmp ult i32 %n, 2
  br i1 %cond, label %c1, label %c2

c1:
  ret i32 1
c2:
  %n1 = sub i32 %n, 1
  %n2 = sub i32 %n, 2

  %fib1 = call i32 @fib(i32 %n1)
  %fib2 = call i32 @fib(i32 %n2)

  %r = add i32 %fib1, %fib2
  ret i32 %r
}

declare i32 @printf(i8*, ...) nounwind


Try maglev!

投稿者 nanki 2009-11-25 21:42:00 GMT

噂のMagLevを試してみた。以下 Mac OS X 10.5.8 での話。

⍟ git clone git://github.com/MagLev/maglev.git # clone repository
⍟ cd maglev
⍟ ./instsall.sh # download and install GemStone

⍟ vim .zshrc
export MAGLEV_HOME=/PATH_TO/maglev
export PATH=$MAGLEV_HOME/bin:$PATH

⍟ rake maglev:start
⍟ maglev-ruby -e "p 1 + 1"
2
⍟ maglev-irb
error , Expected nil to be a Boolean.,
          during /..../maglev/bin/maglev-irb
ERROR 2085, Expected nil to be a Boolean. (RuntimeError)

maglev-irb は動かない><

参考:

やはりRubyでは 〜Scalaの無名関数に憧れて〜

投稿者 nanki 2009-10-29 06:18:00 GMT

憧れシリーズ第二弾。

Scalaの勉強でもしようかな、と思ってScalaの本を開いたら、Scalaでは無名関数を_(アンダースコア)を使って定義できるらしい。 Rubyにおけるそれの実現可能性に考えが行ってしまって、Scalaの本を読むのはそれでおしまいになったのだ…

Rubyでも、

[1, 2, 3].map(_ * 2) # => [2, 4, 6]

とか書きたいよね。

Rubyにはもともと、mapなどのブロックを取るメソッドに無名関数(Proc)を引数として渡すことができる

[1, 2, 3].map(&:to_s)

この例では、:to_s は Symbol だが、Proc を返すSymbol#to_proc を定義しておくと、それが呼ばれてよしなにしてくれる。Symbol#to_proc はActiveSupport などで定義されているので、Rails使いにはおなじみだろう。

この仕組みを利用して、 _ に対して送られるメッセージを保存しておいて、to_proc される時に適当なProcを返すような何かを作ればよい。

module Scala
  class LazyCall
    instance_methods.each do |v|
      undef_method(v) unless %w(__id__ __send__).include?(v)
    end

    def initialize(v = nil)
      @v = v
      @msgs = []
    end

    def method_missing(*args, &block)
      @msgs << [args, block] unless args == [:respond_to?, :to_proc]
      self
    end

    def to_proc
      proc do |v|
        @msgs.inject(@v||v) do |r, m|
          r.__send__(*m[0].map{|a|LazyCall === a ? a.to_proc[v] : a}, &m[1])
        end
      end
    end
  end

  def _(v = nil)
    LazyCall.new v
  end

  # _0, _1, ...
  (0...3).each do |i|
    define_method("_#{i}"){LazyCall.new[i]}
  end
end

include Scala

そうしてできたのがこれ。

これを使うと…

%w(a b c d).map(&_ * _.to_i(16))
# => ["aaaaaaaaaa", "bbbbbbbbbbb", "cccccccccccc", "ddddddddddddd"]

[[1, 2], [2, 3]].map(&_0 + _1)
# => [3, 5]

_(Math).sqrt(_0 ** 2 + _1 ** 2).to_proc[[3, 4]]
# => 5.0

& の後に括弧が要ると思っていたがそんなことはなかったぜ。

メッセージをフックする関係上、直接 Math.sqrt(_0 ** 2 + _1 ** 2) とは書けないけど、そう書きたい人はブロック使ってください。

以下簡単な説明

  • _ はLazyCallのインスタンスを返し、受け取ったメッセージを引数と共に保存。
  • [:respond_to?, :to_proc] をはじいているのは、引数として渡される時にこの問い合わせが発生するので、それを無視するため。(副作用として、無名関数では.respond_to? :to_proc が使えなくなると思う)
  • to_proc内で、保存したメッセージを、procの引数に送り直している。
  • 保存された引数の中に、LazyCallのインスタンスがある場合は、call してその結果と置き換えている。これによって、_ * _ のような表記が可能になる。
  • _0は、_.[0]のエイリアス

二夜にわたるProxyObject特集、いかがでしたでしょうか。さて、来週からは…

追記:2009/10/30

Scalaの _ (プレースホルダ構文と呼ぶらしい) は _ + _と書いたとき、二つの _ が同じものを意味しないそうです。

と、閉じた本の続きに書いてあった。

あと、_0 などを使うと、20倍くらい遅い。どうしたものか。


たぶんRubyでは 〜 Maybeモナドに憧れて 〜

投稿者 nanki 2009-10-28 14:25:00 GMT

HaskellにはMaybeモナドというのがあって、エラー処理をかなり適当な感じに書けてとても便利そう。

一方、多くのプログラミング言語では、

request.mobile && request.mobile.docomo?

File.open('example.txt').read rescue nil # これはすこし横着

こういった記述を頻繁に使う必要があり、なんとかしたい。

そこで、

class Never
  instance_methods.each do |v|
    undef_method(v) unless %w(__id__ __send__).include?(v)
  end

  def method_missing(*args)
    self
  end

  def end
    nil
  end
end

class Maybe < Never
  def initialize(value)
    @value = value
  end

  def method_missing(*args, &block)
    Maybe.new @value.__send__(*args, &block)
  rescue Exception
    Never.new
  end

  def end
    @value
  end
end

class Object
  def maybe
    Maybe.new(block_given? ? yield : self)
  rescue Exception
    Never.new
  end
end

上のようなコードを実行すると、

request.mobile.maybe.docomo?.end # => true/false or nil

File.maybe.open("file_does_not_exist.txt").read.end # => nil

こういう風に書く事ができるようになって幸せ。 途中のどこかで失敗すると、単にnilが返る。

このように、包んだオブジェクトのフリをするオブジェクトを使う手法はRailsでは多用されていて、読んでみると割と楽しい。ProxyObjectとか呼ぶらしい。

class Maybe < Never のあたりが、

子「お父さん、運動会絶対見に来てね」
父「絶対行くぞ」

一週間後

子「お父さん、運動会絶対見に来てね」
父「たぶん…」

というような会話を想像してしまって、とても人間的。

参考:

今日のgolf - るびまゴルフ第七回

投稿者 nanki 2009-09-14 15:02:00 GMT

月に一度のgolf. というか、人がやっているのを目にすると、手を出したくなってくる。
たぶん、子供がプラモデル組み立てているのを見て「ちょっとお父さんにかしてみなさい」というタイプ。

結局、前回の最短は23Bだったらしい。変数名まで同じだった :)
文字数を削るという共通の目的が、変数名から意味すら奪うのだろうか。

20Bという噂はなんだったんだろう…

反省を生かして、今回は、27Bまで縮んだところで寝かせておく。

続きにあるのはお気に入りの答えだが、パー。

追記: 2009/09/17 いくつかの方針で使っている方法を組み合わせたら23Bになった。驚き。

参考:

Windowsを自動化 - EventGhost便利

投稿者 nanki 2009-08-12 22:40:00 GMT

eventghost

InternetExplorerのテスト用に飼っている、VMWare上のWindowsに新たな使命が課せられた。 携帯シミュレータでのテストだ。

ただ、シミュレータは3キャリア分あって、操作方法も全部違うので、これからげんなりすることを思うとげんなりする。

そこで、とりあえず、一発でreloadができるようにならないか方法を探してみた。

ページのリロード

EventGhost というのがあるらしいので、ダウンロードする。 ページのリロードは、指定した名前のウィンドウを探して、F5キーを押すことで実現。これを、3キャリア分設定。(ソフトによってキーは違う)

あっさりとできてしまった。

キャプチャ

それだけだと面白くないので、リロードした後、画像をキャプチャするようにした。 IrfanViewには、起動オプションでアクティブなウィンドウの内容をキャプチャする機能があるらしいので、それを使う。 起動オプションこんな感じ。

i_view32.exe /capture=3 /convert="\\\\.host\Shared Folders\Public\softbank.png"

ウェブサーバ

さらに、プラグインを見てみると、WebServerというのがある。 このプラグインを追加すると、指定したポートでHTTPサーバが起動し、指定したフォルダの内容が見られるようになる。

さらに、クエリーストリングに、HTTP.reload という文字列をつけてGETなどすると、同じ名前のイベントが発生して、アクションをトリガーできるようになるらしい。

そんなわけで、最終的にスクリーンショットのような構成になり、Safariから、http://192.168.1.1/?HTTP.reload などとすると、リロードしてスクリーンショットが見られるようになった。 (スクリーンショットが撮られるまでにはタイムラグがあるので、javascriptで定期的に画像をリロードする)

ウェブサーバ機能はかなり便利。

問題点

  • リロードの終了を検知できないので、2秒待つ、みたいなことをしないといけない。
  • アクティブなウィンドウをキャプチャするので、排他的にしか処理できない。
参考:

chm.rbのバグ?

投稿者 nanki 2009-08-11 22:54:00 GMT

とあるchmファイルをWindowsで見ていて気がついたのだが、一つのキーワードに複数のドキュメントが割り当てられている場合がある。

同じファイルを、Macで見ると、最初のコンテンツしか表示されない。

調べてみると、chmlib のRuby bindingである chm が原因らしい。

そもそも、chmのインデックスは下記のような形式のドキュメントになっていて、chmの中の、chm.rbでこれをパースしているのだが、キーワードが複数のドキュメントに対応する場合が想定されていないようだ。

…
<li><object type="text/sitemap">
  <param name="Name" value="animal">
  <param name="Name" value="dog">
  <param name="Local" value="dog_doc">
  <param name="Name" value="cat">
  <param name="Local" value="cat_doc">
</object>
…

普通の感覚ではこれを見ても一番上のキーワードが下の方まで有効だと思えないのだが…

あと、目次(Topic)を読むところが、case-sensitiveになっていたので、目次が取れていなかった。

コミットしてから気がついたけど、ゴミが…

参考:

Chemr高速化

投稿者 nanki 2009-04-21 18:46:00 GMT

今回のあらすじ

Flex のドキュメントを、オフライン時にも使えるようにしようと企んだ nanki は、coderepos:chm-generators を手にいれ chm ファイル作ってみるが、サイズが150MBもあるので、Chemr 本体に手を加えて、gzip 圧縮に対応することによって無事50MBにまでスリム化することに成功する。が、よく使うリファレンス群はそもそもサイズが5MB程度なので、たいして役に立たないことに気がつき衝撃を受ける。

これは巨大な chm を作って対抗するしかない、とマシンにインストールされた全ての gem の rdoc をchm 化するが、今度はインデックスが大きすぎるためか検索がもたつくことに気付く。

「これでは仕事ができない!」

不当な怒りに燃えた nanki は、よりよい開発環境を手に入れるために Chemr に改造を施し、高速化することを決意したのだった。

果たして戦いの果てに未来はあるのか!?

結果

一回のインクリメンタル検索処理あたり、0.3~1秒程度かかっていたのが100倍くらい速くなった。 体感では100倍とはわからないが、もたつきが感じられないレベルになった。

インデックスの最初の二文字を抜き出してHashで持ち、検索文字列の最初の二文字でO(1)でしぼりこむ仕組み。

高速化の恩恵は最初の数文字の偏りに大きく依存すると思うけど、そもそもそんな状況では、インクリメンタル検索が快適ではないので気にしないこと。

!DOCTYPE 宣言があると外部CSSが効かない(詳細不明)問題とか、ruby-cocoaでsize/countが無限再帰になる問題とか、Chmerとtypoする問題などにも嵌って大変だった。

その後、バージョン違いがたくさん(railsだけで5個くらい)あったgemを削除しまくったので、普通に速くなってあんまり意味がない。

gem を300種類くらい入れて複数のバージョンを保持しているような人しか恩恵が得られないかも。

ちなみに、もたつきが気になるというのは、僕のタイプ速度より速く、キーリピートより遅いくらい。つまり全然支障はない。

codereposのは古いっぽい…?

参考:

僕はあんまり携帯HTMLをいじらないけど、タイトルのような問題があるという話はよく聞く。

また、CSSにはスコープの概念がないので、TinyMCEなどのWYSIWYGエディタを使っていると、Wordなどから<style>タグを含む断片が貼付けられて、ページ全体のスタイルに影響を与えてしまう、などといったことが起こる。

こういった問題への対応策として、CSSのインライン化が有効に働きそうなので、調べてみた。 参考に挙げているが、Perl/PHP では、こういったライブラリが存在しているらしい。

我らが(?)Rubyはというと、(最近遊びでCSSParserを書いたので、なければ作ろうと思ってたけど)やっぱり存在していて、これが結構便利そう。

TamTam: Inline CSS

しかし、こんな名前で公開されても…。見ても気付かないよ…

インストール

$ sudo gem install tamtam

コードがドキュメント、とばかりに、主要な部分を読んでみた。 使い方を見てみよう。

使い方

TamTam.inline
  :css => '.a { background-color:red }',
  :body => "<div class='a'></div>"
#=> "<div class="a" style="background-color: red;"></div>"

素晴らしい。

また、:documentを使うことによって、HTML内の<style>タグの内容をそのまま使うこともできる。

TamTam.inline
  :document => "<style>.a { background-color:red }</style><div class='a'></div>"
#=> "<style>.a { background-color:red }</style><div class="a" style="background-color: red;"></div>"

スタイルを適用した後の余計なclass属性は、元から存在するclass名と衝突するかもしれない。 そんなあなたには、:prune_classes => trueというそれらしいオプションがあるのだが、 バグなのか何なのか、スタイルを適用する前にclassを全部取りさってしまうので(僕の)望む動きとは違うようだ。

TamTam.inline
  :document => "<style>.a { background-color:red }</style><div class='a'></div>",
  :prune_classes => true
#=> "<style>.a { background-color:red }</style><div></div>"
# 適用されてない!

携帯電話…

携帯電話用に使う場合、<link>タグを認識する部分を自分で書かないといけない。

それと、聞いた話では、携帯電話の場合は通信量を減らすために、style='background-color: …'よりも、bgcolor='…'が好まれるそうだ。

CSSだけでは属性を指定するという使い方は出来ないので、その場合も独自に拡張する必要がありそうではある。

参考:


Mac OS X で Wii Remote API を使う

投稿者 nanki 2009-03-22 21:22:00 GMT

Canvasを使ったWii用ゲームを作ってみた (Kanasansoft Web Lab.)

Nintendo Wii に載っているOpera にはWii Remote APIなるものがあって、WiiリモコンとCanvasを使って色々できる。

うちには、OperaもWii のコントローラ(だけ)もあるのに、kanasan の力作が遊べないなんて!ありえない!

というわけで、Wii Remote API のふりをするコードを書いてみた。


WiiFake: emulate Wii Remote API on Mac OS X. from NANKI Haruo on Vimeo.

requires at runtime

How to use.

  1. Copy WiiRemote.framework to your ~/Library/frameworks/ directory.
  2. WiiFake を落としてくる。
  3. Wii リモコンの 1 2 keyを押したままサーバを起動する。
    $ ruby server.rb
  4. このbookmarkletを起動 WiiRemote bookmaklet
  5. 必要に応じてページの初期化処理を呼び出す。
    (上記kanasanのページだと、javascript:initialize())

仕組み

bookmarklet で読み込んだ WiiProxy.swf から localhostに立てたRubyサーバに繋いで、JSON形式で受け取った情報を、javascriptの世界に渡しているだけです。

テスト

Safariでしかテストしてない;;

画質のテストのため、同じムービーをYoutubeにもアップロードしてみた。

参考: