記事の内容
Haskellのラムダ式に慣れたい!!
ラムダ式は、さまざまなプログラミング言語に登場します。
とくに、Haskellの場合、関数を中心に構成していくので、ラムダ式はとても重要な考え方です。
この記事では、
- Haskellにおけるラムダ式の例を豊富に紹介します。
- Haskellの基礎であるカリー化についても案内します。
上記特徴を求めている人はぜひ読んでみてください。
ラムダ式とは?
一言で表すならば、名前の無い関数です。
通常の関数定義:
add x y = x + y
これは次のようなラムダ式で書き換えることができます:
\x y -> x + y
この \x y -> x + y
は、「x
とy
を引数に取り、x + y
を返す関数」です。
ラムダ式を使ってみる
例1
リストへのmap
map (\x -> x * 2) [1, 2, 3]
-- => [2, 4, 6]
map
はリストの各要素に関数を適用します。ここでは「2倍にする無名関数」を使っています。
例2
タプル (a,b)
に対して、合計を計算する無名関数です。
map (\(a,b) -> a + b) [(1,2), (3,4)]
-- => [3, 7]
例3
フィルタで条件を絞る
filter (\x -> x > 10) [4, 12, 5, 18]
-- => [12, 18]
無名関数 \x -> x > 10
によって、10
より大きい要素だけを選びます。
例4
リスト内包表記と合わせる
[ f x | x <- [1..5], let f = (\y -> y * y) ]
-- => [1,4,9,16,25]
f
にラムダ式を入れて平方を計算します。
例5
map
を使って、文字列のリストをすべて大文字に変換する。
map (\s -> map toUpper s) ["haskell", "fun"]
-- => ["HASKELL", "FUN"]
例6
filter
とラムダ式で、偶数だけを取り出してみる。
filter (\x -> x `mod` 2 == 0) [1..10]
-- => [2,4,6,8,10]
ラムダ式をネストする
ラムダ式は入れ子にできます。
(\x -> (\y -> x + y)) 3 5
-- => 8
これは、x
に 3
を適用し、その結果の関数に y = 5
を適用するという意味です。
例1
ネストされたラムダ式で x*y + z
を計算する関数を定義する。
(\x -> (\y -> (\z -> x * y + z))) 2 3 4
-- => 10
x = 2
y = 3
z = 4
と順に適用され、最終的に 2 * 3 + 4 = 10
となります。
例2
条件に応じた分岐。引数 x
の値によって分岐させています。
(\x -> if x > 0 then "positive" else "non-positive") 5
-- => "positive"
例3
無名関数を関数に渡す。
let applyTwice f x = f (f x)
applyTwice (\n -> n + 1) 5
-- => 7
例4
ネストしたラムダ式を使って、条件によって異なる関数を返す。
(\x -> (\y -> if x > y then x else y)) 5 8
-- => 8
カリー化とは?
Haskellでは、関数は1引数しかとらないのが基本です。複数の引数をとる関数は、関数を返す関数として表現されます。
たとえば:
add x y = x + y
これは実はこう解釈されます:
add = \x -> (\y -> x + y)
これがカリー化です。
カリー化とは、カリー化とは、複数の引数をとる関数を、引数を1つずつ受け取って“関数を返す関数”の連鎖に変換することです。
部分適用の例
add3 = add 3
add3 5
-- => 8
add 3
は \y -> 3 + y
という関数になります。
カリー化は部分適用と非常に相性が良く、柔軟な関数設計を可能にします。