人力検索はてな
モバイル版を表示しています。PC版はこちら
i-mobile

Rubyのlambda,proc関数の使い方が良く分かりません。
「こういうときに使うと便利」という例があれば教えてください。


●質問者: garyo
●カテゴリ:インターネット ウェブ制作
✍キーワード:Ruby 関数
○ 状態 :終了
└ 回答数 : 5/5件

▽最新の回答へ

1 ● dankogai
●20ポイント

手前味噌を一つ。

Dan.the.Occasional.Rubyist

◎質問者からの返答

ありがとうございます。

カリー化が複数の引数を持つ関数を1つの引数の関数にすることらしく、確かにlog a Xが引数1つづつの関数で表されているのは分かったのですが、引数を1つの関数にするとどういうメリットがあるのかまだ良く分かっていません。


2 ● cuzic
●20ポイント

http://www.yahoo.co.jp/

URL はダミーです。

lambda とか proc とかを使うと、ある種の手続きをオブジェクトにすることができて、引数などとして渡すことができるようになります。

そうすると、たとえば /aaa/ にマッチするときは、文字列を xxx と処理して、/bbb/ にマッチするときは yyy のように処理するということができるようになります。

同じようなことは、ファクトリーパターン+継承(ポリモーフィズム)でできますが、lambda を使った方が簡潔です。

◎質問者からの返答

ありがとうございます。

CやC++ではその概念がない(コールバック関数とか、関数ポインタはありますが)ので、どのような時に使うと便利なのか分からず質問してみました。

ブロックを引数にとるイテレーターがすごく便利なのは実感していますが、手続き({puts x}みたいな)を変数に入れて(a=proc{|x|puts x};a[1])使う場面というのが中々想像できないです。lispとかやられてた方には自明なのでしょうか?


後、lambda関数とλ計算は同じものなのでしょうか?http://d.hatena.ne.jp/keyword/%a6%cb%b7%d7%bb%bb

上記に書いてあるλを使った式はlambdaでも書けるのでしょうか?

Rubyはオブジェクト指向言語ですが、関数言語の機能も含んでいるのでしょうか。


3 ● 水谷敏行
●20ポイント

ファイナライザを定義するときに使います。

http://www.ruby-lang.org/ja/man/?cmd=view;name=ObjectSpace

◎質問者からの返答

ありがとうございます。

デストラクタに「やること」を引数で渡すわけですね。

def initialize と同様に def finalizer のように定義するのかと思っていました。


4 ● kazutanaka
●20ポイント

http://capsctrl.que.jp/kdmsnr/wiki/bliki/?Closure


Rubyのブロックは、関数内部で暗黙にProcオブジェクトに変換されています。

ブロックはlambda,procのシンタックスシュガーと考えればよいでしょう。

つまりブロックが使えていれば、lambdaを使いこなせているのです。

上記の記事でMartin Fowlerも明示的にlambdaを使うことは少ないと書いています。


ブロックは末尾引数に&を付ければ受け取ることができ、

その値はProcオブジェクトになります。

def setBehaviour(&block)
 @block = block # block.class => Proc
end

def doBehaviour
 @block.call("hoge")
end

setBehaviour() {|x| puts x}
doBehaviour()

ブロックのままだとメソッド内でyieldするしかありませんが、

ブロックがProcになると変数に代入できるので、

変数に記憶しておけば、同じ動作を繰り返し使えるようになります。


コードをブロックで渡すだけで済むなら、ブロックでよいのです。

しかし、コードをブロック形式で渡せない状況であれば

lambdaを明示的に使うことになるでしょう。

例えば、複数のコードブロックを渡したい場合とか、

名前付き引数でコードブロックを指定する時とかが思いつきます。


http://api.rubyonrails.org/classes/ActiveRecord/Validations/Clas...


たまたま開いていた上のActiveRecordのvalidationでもlambdaを使ってますね。

class Person < ActiveRecord::Base
 validates_numericality_of :value, :on => :create,
 :if => lambda { |user| user.signup_step > 2 }
end

こういうのはフレームワーク側で面倒見切れないので、

利用者側が外部からlambdaで指定するわけです。


http://ja.wikipedia.org/wiki/%E3%82%AF%E3%83%AD%E3%83%BC%E3%82%B...


もしlambdaを使いこなしたいのであれば、引数で受け渡せることに加えて

レキシカルクロージャという概念も知っておいた方がよいでしょう。

上のWikipeadiaのJavaScriptカウンタをrubyで書いてみるとこんな感じ。

def make_counter(base=0, inc=1)
 lambda {base+=inc}
end

c = make_counter(1,2)
10.times {puts c.call}
◎質問者からの返答

詳しく説明頂きありがとうございます。

>つまりブロックが使えていれば、lambdaを使いこなせているのです。

procが使えれば大体使いこなせていてさらに細かな動作をさせたいときにlambdaを使うというイメージでしょうか。

lambdaがλ関数であればチューリングマシンと同値。つまりlambda関数さえあれば全てのプログラムが記述可能なわけでしょうか。

mixiの某トピで「yieldとblock.callどっちを使いますか」というのがあってblock.callが良く分からなかったのですが、説明を見て分かったような気がします。

C/C++/Java/C#などには「クロージャー」の概念がないので凄く興味があります。

以前、以下の質問でRubyを薦めたのですが、質問者の方はPHPを選ばれたので残念に思ったことがあります。

Rubyには他の言語にない先進的(逆にLispから受け継いだのでいにしえの術かも)な機能があるのでそれを説明したかったのですが、言葉で表せなかったのが残念です。Rubyを使っているだけで色々勉強になります。

http://q.hatena.ne.jp/1194256707


5 ● kazutanaka
●20ポイント

>procが使えれば大体使いこなせていて

>さらに細かな動作をさせたいときに

>lambdaを使うというイメージでしょうか。


Proc.new, proc{}, lambda{} は同じものです。

(微妙な違いはありますが)

それらを直接使うことはあまり必要ないでしょう。


ほとんどの場合、より高度な構文である

ブロックだけで済んでしまうのです。

(昔はイテレータ、今はブロックと呼びます)


ブロックには「関数に1つしか受け渡せない」

「変数に代入できない」という制約があり、

それを超えてコードの受け渡しをしたいときには

lambdaを明示的に使わないとできません。


>lambdaがλ関数であればチューリングマシンと同値。

>つまりlambda関数さえあれば全てのプログラムが記述可能なわけでしょうか。


ラムダ関数は単なる語源ぐらいに考えた方が現実的だと思います。

Rubyのlambdaは単純にコードをオブジェクト化しているだけです。

回り道かもしれませんが、LispかSchemeを学んだらいいのでは?


http://practical-scheme.net/gauche/index-j.html

◎質問者からの返答

ありがとうございます。

>ブロックには「関数に1つしか受け渡せない」

>「変数に代入できない」という制約があり、

>それを超えてコードの受け渡しをしたいときには

>lambdaを明示的に使わないとできません。

なるほど、そういうわけなんですね。良く分かりました。

関連質問


●質問をもっと探す●



0.人力検索はてなトップ
8.このページを友達に紹介
9.このページの先頭へ
対応機種一覧
お問い合わせ
ヘルプ/お知らせ
ログイン
無料ユーザー登録
はてなトップ