Haskellerへの道 #6 - 関数合成

Last Edited: 6/18/2024

このブログ記事では、関数型プログラミング(Haskellを含む)において重要な概念である関数合成の概念を紹介しています。

Haskell & Composition

関数合成

関数合成は、二つの関数を取り、それらを組み合わせて新しい関数を作る概念です。h(x)=f(g(x)) Haskellでは、関数合成は以下のように表現されます。

( . ) :: (b -> c) -> (a -> b) -> a -> c
(f . g) === (\x -> f(g x))

これがどのように役立つのでしょうか?実際の例を見てみましょう。

descSort = reverse . sort

上記のように、関数を合成することで降順ソートを適用する関数を簡単に定義できます。また、mapに対しても非常に便利です。

map2D = map . map --- 最初のmapは行を反復処理するため、2番目のmapは行内の要素を反復処理するため
map2D (\x -> 2*x) [[1,2,3],[2,3,4]] --- Output: [[2,4,6],[4,6,8]]

このようにして、2次元リストに対するマッピングが可能です。n次元配列に対するマッピング関数も、n回のmap . mapの使用で構築できます。

ドル記号 ($)

一行で多くの関数を使う場面に遭遇したとき、多くの括弧を書くことにストレスを感じることがあります。 幸いにも、Haskellにはこの構文を簡略化する方法があります。

($) :: (a -> b) -> a -> b
f xs = map (\x -> x + 1) (filter (\x -> x > 1) xs)
f xs = map (\x -> x + 1) $ filter (\x -> x > 1) xs

括弧を書かずに、$を使って別の関数を実行することを示すことができます。

(.) vs ($)

どちらを使うかについて混乱することがあるかもしれませんが、多くの場合、それはあなた次第です。ただし、 .は二つの関数を組み合わせて新しい関数を作り出し、$は二つの関数を連続して適用するための構文であることを 覚えておく必要があります。次の例が混乱を解消するのに役立つかもしれません。

add1 x = x + 1
add2 x = x + 2
 
--- For .
add3 = add1 . add2 --- VALID (x+2)+1
add3 x = add1 . add2 x --- INVALID! 関数と値(add2 xの結果)を.で組み合わせることはできません!
 
--- For $
add3 = add1 $ add2 --- INVALID! add1はNumを入力として受け取るだけで、関数を入力として認められません。
add3 x = add1 $ add2 x --- VALID y=(x+2), y+1=結果

個人的には、再利用可能な関数を構築するときは.を、その組み合わせを一度だけ適用するときは$を使うことを好みます。

クイズ

この記事では、学習した内容を確認するためのクイズを設けます。記事のメイン部分を読んだ後に、ぜひ自分で問題を解いてみることを強くお勧めします。各問題をクリックすると答えが表示されます。

リソース