Proc, Lambda in Ruby

陳漢庭
6 min readOct 2, 2020

--

由上圖可以知道Proc跟lambda是同一個類別,Proc跟lambda是Ruby很常見的語法,它們的概念非常相似,也有很多值得探討的地方。

參考文章

這是我看到講述 Proc / Lambda / Block 最好的文章之一。

Block 無法獨立存在

在Ruby程式語言,Block 不是物件不能單獨存在,Ruby 有內建兩個方法使 Block 物件化且單獨存在:Proc 和 Lambda。

如何讓 Proc / Lambda 獨立存在:使用Block

Proc 可以將 Ruby 的程式碼保存起來,並且在需要的時候再執行它,或當作 Block 傳入其他函數。在 Proc.new 後面接一個 Block 就可以產生一個 Proc 的物件,物件化後就是一個參數,接著可以使用 call 方法來執行 Block 內的程式碼。

下面為各種使用call 的方式:

我們拿JS來做比喻好了。以下圖來說,我們了解到a, b, c 在 javascript 的世界中扮演的角色為lambda,lambda指的是匿名函數(Anonymous Function)。當function call相當於lambda直接被執行,跟function後面直接加上括號的意思是一樣的(Immediately Invoked Function Expression, or IIFE)。

Proc / Lambda return

上述這篇很詳細的講到Lambda與Proc的差別。但總之個人認為比起Lambda,Proc的雷非常多,像是 Proc 如果寫了 return 之後就不會繼續執行了。

def test_proc
puts 'start'
hi_proc = Proc.new { return 'Stop here.'}
hi_proc.call # 止於該行
puts 'end' # 該段就不會執行
end

若為lambda的話就不會遇到這種問題,return完後還可以繼續執行。舉第1個例子(源自:這篇):

def test_return(callable_object)
callable_object.call * 5
end

la = lambda { return 10 } # 也可寫成 la = ->{ return 10 }
pr = proc { return 10 } # 也可寫成 pr = Proc.new { return 10 }


puts test_return(la) # 50
puts test_return(pr) # 顯示 LocalJumpError 錯誤訊息

第2個例子(源自:這篇):

def test_proc
pr = Proc.new { return 10 }
result = pr.call
return result * 5
end

def test_lambda
la = lambda { return 10 }
result = la.call
return result * 5
end

puts test_proc # 10
puts test_lambda # 50

嚴謹的 Lambda

由上例我們可以知道,當正常的呼叫他們值都一樣,但例2跟例3我們可以發現,當例2沒有給值的時候ruby會預設給它nil(不嚴謹),例3則會噴錯。Proc.new 在model scope使用上比較不適合,尤其是當如果model發生問題而要debug的話真的有可能會找到瘋掉,反之lambda在不符合格式的狀況,會跳出Error,顯然Proc和lambda在這邊就有很大的差別。

What is &

&在ruby的本質是傳遞block用。由上例我們將 {1+1}的block傳遞進去,而這種寫法跟以下寫法一樣:

由上述例子,我們可以解讀成(&block)進去block裡面會轉成proc並且直接執行。那其實上面的寫法也可以在其他地方再執行,例如寫成以下的形式:

下例yield的例子印出的結果和上面一樣,我們可以得出一個結論:yield只是把(&block)的寫法再簡化

看完上面的講解再看下面的例子就不會那麼難懂了。square在這裡是一個Proc,那在block裡面執行(也就是call)的寫法跟(&block)的寫法如出一徹。

下面這種寫法意思也跟上面一樣,只不過主角從proc變成methods

to_proc

Some methods take a block, and this pattern frequently appears for a block — StackOverflow

:foo.to_proc # => ->x{x.foo}

to_proc的用法可以看我寫的另外一篇文章:

其他語法

介紹一下Ruby 的很像 Promise的寫法,但不是Promise(這是我們前端教的):

下面這篇連結也介紹了Proc composition的用法 🤣

參考資料:

--

--

陳漢庭

由於零散的紀錄過了一段時間之後就看不懂了,於是為了強迫自己用故事的方式記錄學到的東西,就開啟我的發文之路。