Scalaで関数型プログラミングを勉強しているが、無名関数がよくわからない。
無名関数はRubyでいうところのブロックとのこと。
なので、慣れ親しんだ言語のRubyで整理してみることにした。
スタート地点
単純に、足し算について考えてみます。
# -*- coding: utf-8 -*-
# ふつうの足し算
def add2(x, y)
x + y
end
p add2(1, 2)
# 関数の抽象
def add3(x, y)
add2(x, y)
end
p add3(1, 2)
ここまではさすがに理解できる。
ブロック渡し
無名関数
そもそも無名関数(Annonimous Functions)とは、名前付けされずに定義された関数。 Function Literal(関数リテラル)、匿名関数といわれることもある。
メリット
- 一度しか使わない関数の名前を付けなくて済む。
- 名前の衝突を考えなくて済む。
- 関数の引数などに直接渡せる
Rubyだと、無名関数はブロックで表現される。do endでも表現される。
明示的に変数として表現する方法とそうでない方法がある。
- 明示的に渡すときは、引数に&をつけて、callメソッドで呼び出す
- 暗示的に渡すときは、yieldで呼び出す
# ブロック渡し(明示的)
def add5(x, y, &proc)
proc.call(x, y)
end
p add5(1, 2){|x, y| x + y}
# ブロック渡し(暗示的)
def add6(x, y)
yield(x, y)
end
p add6(1, 2){|x, y| x + y}
関数値
Procedure Values。関数を値としてメモリ上に保持すること。
Rubyでは、ブロックをProcオブジェクトとして、メモリ上に名前をつけて束縛したものが、それにあたる。
lambda, procとして表現する方法がある。callメソッドで呼び出す。
# 関数値の導入
def add4(x, y, proc)
proc.call(x, y)
end
proc = lambda{|x, y| x + y}
p add4(1, 2, proc)
# ラムダの糖衣構文
p add4(1, 2, ->(x, y){x + y})
カリー化
そして、よく分からない概念が、カリー化。
複数の引数をとる関数を、
- 引数が「もとの関数の最初の引数」で
- 戻り値が「もとの関数の残りの引数を取り結果を返す関数」
であるような関数にすること。
部分適用を容易にすることが可能になるというメリットがあるらしい。
# カリー化
curry = lambda{|x| lambda{|y| x + y}}
p curry.call(1).call(2)
# ラムダの糖衣構文
curry2 = ->(x){->(y) {x + y}}
p curry2.call(1)
p curry2.call(1).call(2)
# カリーの糖衣構文
curried_proc = proc.curry
p curried_proc.call(1)
p curried_proc.call(1).call(2)
実行結果
この結果をみると、Procオブジェクトとしてメモリ上にあることがよくわかる。
3
#<Proc:0x007fd286805e48@sample.rb:45 (lambda)>
3
#<Proc:0x007fd286805b28 (lambda)>
3