7

もしも

*Main> :t concatMap
concatMap :: (a -> [b]) -> [a] -> [b]

*Main> :t replicate
replicate :: Int -> a -> [a]

それはどのように機能しますか

*Main> :t concatMap . replicate
concatMap . replicate :: Int -> [b] -> [b]

与えられた:

*Main> :t (.)
(.) :: (b -> c) -> (a -> b) -> a -> c

?

つまり、関数合成についての私の理解は、関数が機能するために引数として期待するものはreplicate何でも返さなければならないということです。しかし、そうではないようです。それで、キャッチは何ですか?concatMap(.)

4

2 に答える 2

19

署名に括弧を追加して並べると、何が起こっているかを確認するのに役立つ場合があります。

replicate :: Int -> (a -> [a])
concatMap ::        (a -> [b]) -> ([a] -> [b])

これで、 とを統合した場合、 の出力がreplicateの入力に適合することは明らかです。この場合、構成の出力タイプは です。concatMapba[b] -> [b]

于 2012-08-03T21:37:32.753 に答える
9

難しさは、おそらく型変数の混乱と、型の統一についてどのように推論するかによるものです。トリックは、他の人が言ったように、 (->) が右結合であることを考慮することです。つまり、次のように並べることができます(混乱を避けるために、各シグネチャに新しい型変数を作成します):

(.)       :: (b         ->  c         ) -> (a    -> b        )  -> a -> c
concatMap :: (q -> [r]) -> ([q] -> [r])
replicate ::                               (Int  -> (s -> [s])

これは基本的に、解決する必要があるいくつかの制約を与えます。「a ~ b」は、「a は b と同じ型である」または同等に「a は b で置換できる」という意味であるとしましょう。

以上のことから、次の事実を推測できます。

a ~ Int
b ~ (q -> [r]) ~ (s -> [s])
c ~ ([q] -> [r])

しかし、b の 2 つの同値は、次のことを示しています。

(q -> [r]) ~ (s -> [s])

それはそれを伴う

q ~ s and [r] ~ [s]

したがって、c を次のように書き換えます。

c ~ ([q] -> [r]) ==> ([s] -> [s]))

2 つの関数を適用して、a と c の置換を (.) の元の型に戻すと、次の結果が得られます。

a -> c ~ Int -> ([s] -> [s]) 

もちろん、これは ghci が報告する形式になっています: Int -> [b] -> [b].

于 2012-08-03T22:19:21.400 に答える