Haskell ラムダ

ホーム   目次


この章では、ラムダ、高階関数、などを説明しています。

ラムダ式

今までは関数の引数を左辺で定義していました。


plusOne x = x + 1

main = do
    print $ plusOne 100
    

実行結果

101

この引数を右辺で定義することもできます。


plusOne = \ x -> x + 1

main = do
    print $ plusOne 200
    

実行結果

201

この右辺の式のことをラムダ式と呼びます。\ (バックスラッシュ)がギリシャ文字のラムダλに似ているからです。

型注釈

型注釈とラムダ式を並べると書式が同じであることがわかります。


plusOne :: Int -> Int
plusOne =  \x -> x + 1

main = do
    print $ plusOne 300
    

実行結果

301

無名関数

ラムダ式は名前のない関数(無名関数)で、それを変数に束縛していると考えることもできます。


a = \x -> x + 1

main = do
    print $ a 400
    

実行結果

401

ラムダ式を変数に束縛しないで使うこともできます。


main = do
    print $ (\x -> x + 1) 500
    

実行結果

501

一度しか使わない関数にわざわざ名前をつけるのが面倒な時、ラムダ式は便利です。

複数の引数

複数の引数を持つ関数は次のように定義できます。


add1 x y = x + y
add2 = \x y -> x + y
add3 = \x -> \y -> x + y

main = do
    print $ add1 100 100
    print $ add2 200 200
    print $ add3 300 300
    

実行結果

200
400
600

実際には、add3が正式な書き方で、add1もadd2も、add3のシンタックスシュガー(糖衣構文)です。糖衣構文とは、複雑な記述を、簡単な記述に置き換える方法です。内部的には複雑な構文が使われています。

高階関数

引数として関数を受け取ったり、戻り値として関数を返す関数を高階関数と言います。

引数として関数を受け取る


higher func = func 200 100

add x y = x + y
sub = \x y -> x - y

main = do
    print $ higher add
    print $ higher sub
    

実行結果

300
100

上のsubでは変数にラムダ式が束縛され、その変数がhigher関数に渡されています。変数を経由せずに、関数にラムダ式を直接渡すこともできます。


higher func = func 200 100

main = do
    print $ higher $ \x y -> x + y
    print $ higher $ \x y -> x - y
    

実行結果

300
100

戻り値として関数を返す


division x = \y -> x / y

main = do
    let division5 = division 5
    print $ division5 2
    print $ (division 5) 2
    print $ division 5 2
    

実行結果

2.5
2.5
2.5

カリー化


add  x y =  x + y
add' x   = \y -> x + y
add''    = \x -> \y -> x + y

main = do
    print $ add   20 30
    print $ add'  20 30
    print $ add'' 30 30
    

実行結果

50
50
50

上記のように引数を分割して、関数をネストさせることをカリー化と言います。実際には、Haskellの関数が受け取ることができる引数は一つだけです。複数の引数を受け取った場合は、関数内部で自動的にカリー化が行われています。

部分適用


add x y = x + y

main = do
    let add20 = add 20
    print $ add20 30
    print $ (add 20) 30
    

実行結果

50
50
50

上記のようにすれば、関数の一部の引数に値を与えておくことができます。

標準ライブラリの高階関数

標準ライブラリで定義されている高階関数を紹介します。

map

第1引数の処理を第2引数のリストに適応した、新しいリストを作ります。同じ処理をするリスト内包表記もあげておきます。


main = do
    print $ map (*2)  [1..5]
    print [x*2 | x <- [1..5]]
    

実行結果

[2,4,6,8,10]
[2,4,6,8,10]

filter

第2引数のリストから、第1引数の条件を満たす要素だけの、新しいリストを作ります。同じ処理をするリスト内包表記もあげておきます。


main = do
    print $ filter (<=5) [1..10]
    print $ [x | x <-    [1..10], x <= 5]
    

実行結果

[1,2,3,4,5]
[1,2,3,4,5]

foldl

リストの要素を左から1つずつ処理しながら集計した、新しいリストを作ります。同じ処理をするsum関数もあげておきます。

foldl :: 集計関数 -> 初期値 -> リスト -> 集計結果

main = do
    print $ foldl (+) 0 [1..100]
    print $ sum         [1..100]
    

実行結果

5050
5050

foldr

リストの要素を右から1つずつ処理しながら集計した、新しいリストを作ります。foldlと比べてみました。


main = do
    print $ foldr (-) 0 [1..5]
    print $ foldl (-) 0 [1..5]
    

実行結果

3
-15


11796 visits
Posted: Jan. 20, 2019
Update: Jan. 20, 2019

ホーム   目次   ページトップ