2008-07-29
■ [scheme][ruby] call/ccの7つの典型的な使い方
わだばさん(でいいのかな?)のところで紹介されていたCall with Current Continuation Patternsをちょっと見てみた。
それによると、callccの典型的な使い方には以下のようなものがあるらしい。
- (無限)ループからの脱出
- 再帰からの脱出
- Cでいうcontinue
- 脱出+再入
- コルーチン
- non-blindな(??)バックトラッキング
- マルチタスク
で、だ。
1, 2, 3は、breakとかcontinueがある言語なら普通にできる。 5や4の一部は、PythonのジェネレータとかRuby1.9のFiberでできる。 7はコルーチンやスレッドを使えばできる。
となるとcallccでしか出来ないことって(この中では)再入とバックトラックしか残らんのだよなぁ。 しかもバックトラックはHaskellだとリストモナドで綺麗に書けたりするし、見た目はカッコいいけど普通にループ回すのより効率が良いわけでもないし。
なんとなく「マクロの機能の8割は他の言語でも可能になりつつある」という話(あ、しまった、まだ書いてないや)とオーバーラップした。
それでも「できるだけシンプル、かつ強力」を志すSchemeとしてはcall/ccの代わりにbreakを導入するとかはまずあり得ないし(それこそcall/ccとマクロでできるよ)、 最後に残った「call/ccでしかできない仕事」はSchemeの力として残りつづける。
ただそれ以外の言語(というか、Ruby)にこれからもcallccが必要かと言われると、説得力のある答えを提示できないのが正直なところだ。 まぁContinuationクラスを無くしてほしくない人は、「再入をうまく使うパターンを考えろ」というのがヒントになるかもね。
■ [ruby] Re: Pythonのデコレータが面白いのでRubyで実装してみた
んー、まぁ一応動いてるんだけど、アノテートみたいにメソッド定義の前に付けられないのがなぁ・・・。
[いい天気 - ずっと君のターンより引用]
「private」みたいにメソッドの直前に付けるのはどうだろ?ということで実装してみた。
Point = Struct.new(:x, :y) class Point extend DeclareArgsDecorator declare_args(Point) def distance_to(other) Math.sqrt( (x - other.x)**2 + (y - other.y)**2 ) end end center = Point.new(0.0, 0.0) puts center.distance_to(Point.new(3.14, 1.592)) puts center.distance_to([2.0, 4])
実行結果。
/Users/yhara/proj/misc/ruby_decorator % ruby foo.ugoku.rb 3.52052041607487 foo.ugoku.rb:10:in `check_args': 引数の型がちがうお (PointじゃなくてArrayになってる) (ArgumentError) from foo.ugoku.rb:8:in `each' from foo.ugoku.rb:8:in `check_args' from foo.ugoku.rb:29:in `distance_to' from foo.ugoku.rb:50
実装はまあ、ふつうですね。yharaはalias_methodを覚えた。
module DeclareArgsDecorator def self.check_args(args, types) if args.size != types.size raise ArgumentError, "引数の数がちがうお" elsif args.zip(types).each do |arg, type| unless arg.is_a?(type) raise ArgumentError, "引数の型がちがうお (#{type}じゃなくて#{arg.class}になってる)" end end end end @@declared_type = nil def declare_args(*klasses) @@declared_type = klasses end def method_added(name) if @@declared_type declared_type = @@declared_type @@declared_type = nil #avoid infinite loop class_eval { alias_method("__original_#{name}__", name) define_method(name) do |*args| DeclareArgsDecorator.check_args(args, declared_type) self.__send__("__original_#{name}__", *args) end } end end end
あとは一般化してmodule Decoratorとか作ればいいんだけど、飽きた。あとあんまりデコレータっぽくない(Pythonのデコレータは関数から関数を作る感じですよね)。
call/ccは普通の人が使うものじゃないのです。<br>新しい例外メカニズムとか、新しいスレッドシステムとか、新しいへんてこりんな構文要素とかを試してみたい人が、そういうものを「処理系自体に手を加えずに」「かつ複数の実装間でポータブルに」作ってみる時につかうものなのです。<br>RubyやPythonや... で実験したい人は、処理系そのものに手を入れればよろしいでしょう。1言語1処理系を前提とするならそれで構わないわけで。(どちらも1言語1処理系の前提は崩れつつありますが)
なんか以前似たような物を作ったことがあります。<br>http://www.kmc.gr.jp/~ohai/diary/?date=20060110#p01<br>このときは Haskell の型宣言ぽく作ろうと考えていた気がします。<br><br>あとこの手のメソッドに細工をする類のメソッドを定義するのは<br>UnboundMethodを使ったほうがきれいに書けるかも。
shiroさん:<br>なるほど…、call/ccは「処理系の内臓が外にはみ出してるようなもの」と思っていいんですかね。<br>マクロがそうであるようにcall/ccも「Scheme使いなら普通に使うもの」かと思ってたんで、Scheme使いの方の意見が聞けて嬉しいです。