6

私はHaskellに比較的慣れていないので、私の質問がばかげているように聞こえたらお詫びします。私は関数の合成がどのように機能するかを理解しようとしてきましたが、誰かが私を助けてくれるのではないかと思っていた問題に遭遇しました。次の2つのシナリオで、関数合成でマップを使用しています。

  • map (*2) . filter even [1,2,3,4]
  • map (*2) . zipWith max [1,2] [4,5]

filter関数とzipWith関数の両方がリストを返しますが、最初のコンポジションのみが機能し、2番目のコンポジションは以下のエラーをスローします。

"Couldn't match expected type '[Int] -> [Int]' with actual type '[c0]'

任意の提案をいただければ幸いです。

4

5 に答える 5

18

の型を思い出してください(.)

(.) :: (b -> c) -> (a -> b) -> a -> c

2 つの関数と初期値の 3 つの引数を取り、合成された 2 つの関数の結果を返します。

これで、引数への関数の適用は、(.)演算子よりも厳密にバインドされます。だからあなたの表現:

map (*2) . filter even [1,2,3,4]

次のように解析されます。

(.) (map (*2)) (filter even [1,2,3,4])

これで、最初の引数は問題map (*2)ありません。type (b -> c)、 where bcis がありNum a => [a]ます。ただし、2 番目の引数は単一のリストです。

Prelude> :t filter even [1,2,3,4]
filter even [1,2,3,4] :: Integral a => [a]

そのため、型チェッカーは、関数が関数を必要とする[a]ときに引数としてa を渡していると文句を言うでしょう。(.)

そして、それが私たちが見るものです:

Couldn't match expected type `a0 -> [b0]' with actual type `[a1]'
In the return type of a call of `filter'
In the second argument of `(.)', namely `filter even [1, 2, 3, 4]'
In the expression: map (* 2) . filter even [1, 2, 3, 4]

だから... 括弧!

演算子を使用し$て括弧を追加します。

map (*2) . filter even $ [1,2,3,4]

または明示的な括弧を使用して、2 つの関数の構成を削除します

map (*2) (filter even [1,2,3,4])

あるいは:

(map (*2) . filter even) [1,2,3,4]
于 2012-05-06T14:06:21.740 に答える
5

次のフォームが有効です。

map (* 2) $ filter even [1, 2, 3, 4]
(map (* 2) . filter even) [1, 2, 3, 4]
map (* 2) $ zipWith max [1, 2] [4, 5]
(\xs -> map (* 2) . zipWith max xs) [1, 2] [4, 5]

ただし、次のことはできません。

map (* 2) . filter even [1, 2, 3, 4]
map (* 2) . zipWith max [1, 2] [4, 5]
(map (* 2) . zipWith max) [1, 2] [4, 5]

どうしてこんなことに?ええと、例えば

map (* 2) . zipWith max [1, 2] [4, 5]

それはと同じです

(map (* 2)) . (((zipWith max) [1, 2]) [4, 5])

(map (* 2))タイプがあり[Int] -> [Int](のデフォルトを想定Int)、(((zipWith max) [1, 2]) [4, 5])タイプが[Int]あり、(.)タイプがある(b -> c) -> (a -> b) -> a -> c([Int] -> [Int]) -> ([Int] -> [Int]) -> [Int] -> [Int]、この非多型の場合、これはタイプが正しくありません。一方、($)タイプ(a -> b) -> a -> bは、または([Int] -> [Int]) -> [Int] -> [Int]この非多型の場合は、次のようになります。

(map (* 2)) $ (((zipWith max) [1, 2]) [4, 5])

よくタイプされています。

于 2012-05-06T14:07:47.967 に答える
5

の結果zipWith max [1,2] [4,5]はリストであり、関数ではありません。(。)演算子には、右のオペランドとして関数が必要です。したがって、2行目のエラー。おそらくあなたが欲しいのは

map (*2) (zipWith max [1,2] [4,5])

最初の例はWinHugs(Hugsモード)ではコンパイルされません。同じエラーが発生します。以下が機能します

(map (*2) . filter even) [1,2,3,4]

2つの関数を構成し、結果の関数を引数に適用するためです。

于 2012-05-06T13:58:32.207 に答える
2

の優先順位が低いため(.)、Haskellは解析します

map (*2) . filter even [1,2,3,4]

なので

map (*2) . (filter even [1,2,3,4])

つまりmap (*2)、(関数)をfilter even [1,2,3,4](リスト)の結果で構成します。これは意味がなく、型エラーです。

これは、@ Theodoreの提案を使用するか、次を使用して修正できます($)

map (*2) . filter even $ [1,2,3,4]
于 2012-05-06T14:08:53.467 に答える
2

マップのタイプを確認すると、次のようになります。(a -> b) -> [a] -> [b]

したがって、aの関数をbに取り、次にaのリストを取り、bのリストを返します。右?

ここで、パラメーターを渡すことにより、aの関数をbにすでに提供しています(*2)。したがって、部分的に適用されたマップ関数[Integer] -> [Integer]は次のようになります。つまり、整数のリストを受け取り、整数のリストを返します。

ここまでは、同じシグニチャを持つ関数を作成(。)することができました。あなたのタイプが何であるかをチェックすると、filter evenそれが次のようになっていることがわかり[Integer] -> [Integer]ます。

この構成は、次のタイプをチェックした場合、関数の最終的な署名を変更しませんmap (*2) . filter even[Integer] -> [Integer]

は、によって期待されるものと同じ署名を持たないmap (*2) . zipWith max [1,2] [4,5]ため、これは当てはまりません。zipWith maxmap (*2)

于 2012-05-06T14:08:59.567 に答える