InfoQ

News

Ruby 1.9 のSymbol#to_procと(入ったばかりの)Procのカリー化

作者 Werner Schuster, 翻訳者 角谷 信太郎 - (株)永和システムマネジメント 投稿日 2008年3月4日 午前12時31分

コミュニティ
Ruby
トピック
プログラミング
タグ
言語,
言語特性
Ruby 1.9での目玉機能といえばスレッド機構の変更やFiber(source)だが、これ以外にも標準ライブラリに加えられた便利な機能がある。Object#tap(source) については既に紹介した通りだ。tapメソッドはメソッドコールのチェインの途中に処理を割り込ませられる便利な機能だ。

tapメソッドがそうであったように、to_procメソッドのアイデアも、少し前からRubyコミュニティでは知られていた。to_proc相当の機能は、Ruby 1.9より前のバージョンでも利用できたのだ。Ruby 1.9 はこの機能をそのままSymbolクラスへと統合した。このおかげで、Symbol#to_procを使うのにライブラリは必要なくなった。


Reg Braithwaite による手短なSymbol#to_procの紹介記事では (1..100).inject(&:+) のようなコードが動くようになったと説明(source)されている。
&演算子はProcオブジェクトをブロックへ変換し、ブロックをProcオブジェクトへ変換します。この場合、&はシンボル :+ をブロックへ変換しようとします。ブロックへの変換にはRuby組み込みの型変換が利用されます。ブロックへの型変換ではまず、Procオブジェクトが与えられているかをチェックします。ブロックが与えられていなければ、引数として与えられたオブジェクトをProcへと変換すべく to_procメソッドが呼び出されます。このとき、シンボル :+ に to_proc メソッドが定義されていれば、それが呼び出されます。Ruby 1.9では、Symbol#to_roc が定義されています。このto_procメソッドは、Procオブジェクトを返します。
つまり、 &:+{ |x, y| x + y }になるということです。

この振る舞いのおかげで次のようなコードを書けるようになる。                                             

plus = :+.to_proc
puts plus.call(1,2) # '3'が表示される

Symbolクラスにto_procメソッドがあるということは、このやり方があらゆるシンボルに通用するということだ。
to_s = :to_s.to_proc
to_s.call(42) # 文字列"42"が返ってくる

 to_procの実装はシンプルだ。Dave Thomas(PragDave)はその動作(source)をこう説明している。                               

def to_proc
 proc { |obj, *args| obj.send(self, *args) }
end

to_procメソッドはProcを生成します。生成されたProcは、オブジェクトを引数にして呼び出されると、渡されたオブジェクトに対してsendメソッドを呼び出します。sendメソッドの第1引数のシンボルは、to_procのレシーバの自分自身です。ですから、たとえば names.map(&:upcase)の場合、namesに格納されている字列をイテレートするわけですが、その際にはnamesの各要素に対してupcaseメソッドを呼び出すブロックがコールバックされます。

この機能のおかげでコードがとても簡潔になるのだが、ひとつ疑問が残る。つまり、これでコードは読みやすくなるのだろうか?これに対する答えはたぶん to_proc がRuby 1.9の標準となったことで変わっていくだろう。なぜなら、いまやSymbolにはかならずto_procメソッドがあるからだ。以前であれば、Symbol#to_procを実現しようとすれば、自分でコードを書くか、Symbolを再オープンしてto_procメソッドを追加するライブラリを使うしかなった。さらに、こうしたコードを理解するにはSymbol#to_procというイディオムを知っていなければならなかった。これについてはRuby 1.9で公式にサポートされたことで、今後はドキュメントでも言及されていくようになるだろう。

それでもやはり疑問は残る。確かに、
 (1..100).map(&:to_s) 
 (1..100).map{|x| x.to_s } 
よりも短く書ける(この例では5文字短かい)。しかし、これは複雑さを増すに見合ったものだろうか? それともやりすぎだろうか?

 Ruby 1.9のProcには他にも追加された機能がある。Porc#curry がそうだ(といってもsvnリポジトリのごく最近のリビジョン(r15459以降)でなければ使えないが)。ruby-core メーリングリストの議論によれば、Proc#curry の機能(source)とは次のようなものだ。
全然難しいことはなくて、
 proc {|x, y, z| x + y + z }.curry
 は、次のようなprocを返すのと同じです
 proc {|x| proc {|y| proc {|z| x + y + z } } }
メソッド名の由来は「カリー化(Currying)(source)」だ。カリー化とは、

カリー化(currying)とは、計算機科学分野の技法の一つ。複数の引数をとる関数を、引数が「もとの関数の最初の引数」で戻り値が「もとの関数の残りの引数を取り結果を返す関数」であるような関数にすること。

つまりカリー化とは、n個の引数を取るProcを1つの引数だけで呼ぶことができるということだ。この場合は(当たり前だが)処理の結果を返すことはできない――処理を実行するために必要な引数が与えられていないからだ。よって、処理結果の代わりに、(n -1)個の引数をとる新しいProcが返される。これが繰り返されて、Procのコードを処理するのに必要なだけの引数が揃ったら、Procは処理を実行してその結果を返す。

 ruby-core メーリングリストの議論スレッドから利用例を紹介しよう。                                           

plus_five = proc { |x,y,z| x + y + z }.curry.call(2).call(3) 
plus_five[10] #=> 15

補足: plus_five は Procであり、[]演算子はProcではProcを実行するようにオーバーライドされている。

注意: Proc#curry が Ruby 1.9 に追加されたのはつい最近である。試してみるには、最新のsvnリビジョン(r15459以降)を利用しなければならない。

原文はこちらです:http://www.infoq.com/news/2008/02/to_proc-currying-ruby19

ブックマーク
digg+,
reddit+,
del.icio.us+,
dzone+,
Hatena

No comments

返信

ジャンル別一覧

メタプログラミングを使ってRubyにプロパティを追加する

Werner Schuster氏が、簡単な例を示しながら、Javaのようなプロパティをメタプログラミングを使ってRubyに追加する方法を示します。

BlazeDSとAMFでWebとデスクトップのアプリケーションを構築する

現在のRIAアーキテクチャにおいて、クライアント/サーバーの通信は重要な位置を占めています。本稿では、James WardとShashank TiwariがアドビによるオープンソースのBlazeDSメッセージングサーバーの世界へ飛び込みます。

業務ソフトに手を加えずに暗号化を実現する~秘文の挑戦~

hibun

ウィルス対策ソフトや情報漏えい防止用のソフトは、いわば影の存在です。ユーザの操作性やGUIを工夫する以上に、いかに目立たない存在となるかにその技術を注ぎ込んでいます。ここでは日立ソフトが開発した「秘文」の事例を紹介します。

Google Chartとgchartrbの紹介

Google Chartは、チャートを作成するためのWebサービスです。本稿では、Google Chartのインターフェースと、Rubyコードから簡単にチャートを生成することができるgchartrbライブラリの説明をします。

SOAを超えて: 動的な業務アプリケーションのための新しいエンタープライズアーキテクチャフレームワーク

全二回からなるこの記事では、ダイナミックビジネスアプリケーション(Dynamic Business Applications:DBAs)の開発についての全体的な眺望を、アーキテクチャと方法論の観点から見ていくことになります。我々のゴールは、「ビジネスの変化や、その他に必要とされる変更に対して、いかにして容易に適応できるアプリケーションを構築していくか」を導きだすことです。

ESB接続形態のオルタナティブ

本稿では、Adrien Louis氏がESBベースのSOAに対する2つの接続形態についての賛否について説明しています。その2つとは、会社での単一のESB対「部門毎」に相互接続するESBによるシステムです。

AjaxプログラマのためのJavaOne2008 -GrizzlyでComet!-

誕生から2年を経てCometは「何が出来るのか」という議論から、「いかに実現するか」という議論に関心が移ってきたように見えます。そこで本稿では同じくJavaOneで数多く取り上げられたNetBeans 6.1とGlassFish v3を使いながら、サンプルを交えてCometを解説していく事にします。

SharePoint Webサービスを始めましょう

この記事では、WSS3とMOSS 2007に難しい設定など一切せず、すぐに利用可能なWebサービスと、Javaと.NETからそのWebサービスを消費する方法に目を向けます。