簡體   English   中英

Haskell:在函數組合中使用map

[英]Haskell: Using map in function composition

我對Haskell相對較新,如果我的問題聽起來很愚蠢,那么道歉。 我一直試圖理解功能組合是如何工作的,我遇到了一個問題,我想知道有人可以幫助我。 我在以下兩個場景中使用函數組合中的map:

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

雖然filter和zipWith函數都返回一個列表,但只有第一個組合有效,而第二個組合會拋出以下錯誤:

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

任何建議將不勝感激。

回想一下(.)的類型。

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

它有三個參數:兩個函數和一個初始值,並返回組成的兩個函數的結果。

現在,函數對其參數的應用比(.)運算符更緊密。 所以你的表達:

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

被解析為:

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

現在,第一個參數map (*2) 它有類型(b -> c) ,其中bcNum a => [a] 但是,第二個參數是單個列表:

Prelude> :t filter even [1,2,3,4]
filter even [1,2,3,4] :: Integral 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]

或使用明確的parens,刪除兩個函數的組合

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

甚至:

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

zipWith max [1,2] [4,5]是一個列表,而不是一個函數。 (。)運算符需要一個函數作為其右操作數。 因此你的第二行錯誤。 可能你想要的是什么

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

你的第一個例子不能在WinHugs上編譯(擁抱模式); 它有同樣的錯誤。 以下將有效

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

因為它組成了兩個函數並將結果函數應用於參數。

以下表格有效:

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])

打字很好。

由於(.)優先級較低,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]的結果filter even [1,2,3,4] (列表),這是沒有意義的,並且是類型錯誤。

您可以使用@ Theodore的建議或使用($)來解決此問題:

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

如果你檢查地圖的類型是: (a -> b) -> [a] -> [b]

因此,它需要a的函數進入b然后是a的列表並返回b的列表。 對?

現在,您已經通過傳遞參數(*2)提供了a到b的函數。 因此,部分應用的map函數最終為: [Integer] -> [Integer]意味着您將收到一個整數列表並返回一個整數列表。

到目前為止,您可以編寫(。)具有相同簽名的函數。 如果你檢查什么是filter even的類型,你filter even會看到它是: [Integer] -> [Integer] ,這里是一個有效的合成候選者。

如果檢查類型: map (*2) . filter even ,則此合成不會改變函數的最終簽名map (*2) . filter even map (*2) . filter even[Integer] -> [Integer]

這不是map (*2) . zipWith max [1,2] [4,5]的情況map (*2) . zipWith max [1,2] [4,5] map (*2) . zipWith max [1,2] [4,5]因為zipWith maxmap (*2)期望的簽名不同。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM