web-dev-qa-db-ja.com

Haskellの関数構成

私は読んでいます this Haskellのチュートリアル。彼らは関数合成を次のように定義しています:

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

ここで何が定義されているかについて私を啓発するであろう例は提供されなかった。

誰かが関数合成がどのように使用されるかについての簡単な例(説明付き)を提供できますか?

28
Fragsworth

関数の合成は、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]

少し短く、エラーの余地が少なくなります。

47
Tom Lokhorst

楽しいサイドノート。関数の合成は、論理の三段論法に相当します。

すべての男性は致命的です。ソクラテスは男です。したがって、ソクラテスは致命的です。

三段論法は、2つの重要な意味を1つに構成します。

(Man => Mortal), (Socrates => Man), therefore (Socrates => Mortal)

したがって...

(b -> c) -> (a -> b) -> (a -> c)

...これは.関数のタイプです。

31
Apocalisp

ザ・ 組成fgは、最初に引数に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)); }
14
David Crawshaw

この例は考案されていますが、

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であるため)。

7
Brian

関数の合成は、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

基本的には、他の機能を使用できる場所であればどこでも使用できます。これは、「これらの機能をチェーン化したい」という、すばやく読みやすい方法です。

5

関数合成に関するHaskellWikiページ: から

desort = (reverse . sort)

現在、desortは、リストを逆にソートする関数です。基本的に、desortは引数をsortにフィードし、次に戻り値をsortからreverseにフィードし、それを返します。したがって、それをソートしてから、ソートされたリストを逆にします。

4
Chris Lutz