私は読んでいます this Haskellのチュートリアル。彼らは関数合成を次のように定義しています:
(.) :: (b->c) -> (a->b) -> (a->c)
f . g = \ x -> f (g x)
ここで何が定義されているかについて私を啓発するであろう例は提供されなかった。
誰かが関数合成がどのように使用されるかについての簡単な例(説明付き)を提供できますか?
関数の合成は、2つの関数を1つの関数に「合成」する方法です。次に例を示します。
次の機能があるとします。
even :: Int -> Bool
not :: Bool -> Bool
そして、上記の2つを使用して独自のmyOdd :: Int -> Bool
関数を定義したいとします。
これを行うための明白な方法は次のとおりです。
myOdd :: Int -> Bool
myOdd x = not (even x)
しかし、これは関数合成を使用してより簡潔に行うことができます。
myOdd :: Int -> Bool
myOdd = not . even
myOdd
関数はまったく同じように動作しますが、2番目の関数は2つの関数を「接着」することによって作成されます。
これが特に役立つシナリオは、明示的なラムダの必要性を取り除くことです。例えば:
map (\x -> not (even x)) [1..9]
次のように書き換えることができます。
map (not . even) [1..9]
少し短く、エラーの余地が少なくなります。
楽しいサイドノート。関数の合成は、論理の三段論法に相当します。
すべての男性は致命的です。ソクラテスは男です。したがって、ソクラテスは致命的です。
三段論法は、2つの重要な意味を1つに構成します。
(Man => Mortal), (Socrates => Man), therefore (Socrates => Mortal)
したがって...
(b -> c) -> (a -> b) -> (a -> c)
...これは.
関数のタイプです。
ザ・ 組成f
とg
は、最初に引数にg
を適用し、次にf
によって返される値にg
を適用する関数です。次に、f
の戻り値を返します。
このアイデンティティは啓発的かもしれません:
f (g x) = (f . g) x
Java/Cのバックグラウンドがある場合は、次の例を検討してください。
int f(int x);
int g(int x);
int theComposition(int x) { return f(g(x)); }
この例は考案されていますが、
sqr x = x * x
inc x = x + 1
そして、x ^ 2 +1を計算する関数を書きたいと思います。我々は書ける
xSquaredPlusOne = inc . sqr
(つまり、
xSquaredPlusOne x = (inc . sqr) x
つまり
xSquaredPlusOne x = inc(sqr x)
f = incおよびg = sqrであるため)。
関数の合成は、2つ以上の関数を連鎖させる方法です。多くの場合、シェル配管に例えられます。たとえば、Unixスタイルのシェルでは、次のように記述できます。
cat foo.txt | sort -n | less
これはcat
を実行し、その出力をsort
にフィードし、そこからの出力をless
にフィードします。
厳密には、これはHaskell $
演算子のようなものです。あなたは次のようなものを書くかもしれません
sum $ sort $ filter (> 0) $ my_list
シェルの例とは異なり、これは右から左に読むことに注意してください。したがって、入力としてmy_list
から始め、次にfilter
を実行し、次にsort
を実行し、次にsum
を計算します。
関数合成演算子.
は、同様のことを行います。上記の例では、数値;が生成されます。以下の例では、関数が生成されます。
sum . sort . filter (> 0)
実際にはリストをこれにフィードしていないことに注意してください。代わりに、新しい関数を作成したばかりで、その関数にいくつかの異なるリストをフィードできます。たとえば、次の名前を付けることができます。
my_function = sum . sort . filter (> 0)
または、引数として別の関数に渡すこともできます。
map (sum . sort . filter (> 0)) my_lists
基本的には、他の機能を使用できる場所であればどこでも使用できます。これは、「これらの機能をチェーン化したい」という、すばやく読みやすい方法です。
desort = (reverse . sort)
現在、desort
は、リストを逆にソートする関数です。基本的に、desort
は引数をsort
にフィードし、次に戻り値をsort
からreverse
にフィードし、それを返します。したがって、それをソートしてから、ソートされたリストを逆にします。