2015-10-06 16 views
0

map的簽名是(a -> b) -> [a] -> [b],這意味着它需要2個參數並返回一個列表。 然而下面的函數,其將一個字符串轉換爲第一個字母大寫的克隆是錯誤的:haskell:地圖的好用法,參數的數目

modernise :: String -> String 
modernise s = unwords . map (\m -> [toUpper (head m)] ++ tail m) (words s) 

良好的版本是:

modernise :: String -> String 
modernise = unwords . map (\m -> [toUpper (head m)] ++ tail m) . words 

的第一個版本被拒絕,一個錯誤說:"too many arguments for the map function";但我給了2個參數(λ函數和words的結果),這是很多參數。

你能幫助我嗎?

+2

對於map函數,我寧願'map(\(x:xs) - > toUpper x:xs)'。一般來說,沒有理由比'x:xs'更喜歡使用'[x] ++ xs',模式匹配幾乎總是優於頭部和尾部。 –

+0

@ReinHenrichs的確,不幸的是,'words'返回一列列表而不是'NonEmpty'列表。 – dfeuer

+0

後人快速提示:我把它作爲X的副本,這是Y的副本。不過,我認爲X和Y之間有一些細微的不同,這個問題不是Y的重複;但X的答案確實解決了這個問題中出現的混亂。 (可能X首先不應該是Y的重複,儘管我可以明白爲什麼它以這種方式關閉。) –

回答

4

在第一個版本,你寫

modernise s = unwords . map whatever (words s) 

通過的.的定義,這意味着

modernise s = \x -> unwords (map whatever (words s) x) 

你可以反而使用了$操作:

modernise s = unwords $ map whatever (words s) 

但你還得幹活的版本是完全地道的和明確的,所以沒有必要改變其結構的那個方面。

+0

這是一個經常犯的錯誤,我想知道爲什麼GHC沒有檢測到它背後的意圖用戶並報告更容易理解的錯誤消息。 –

+2

@ErikAllik,讓類型檢查器給出可用的錯誤信息已經足夠困難,而不會嘗試烘焙知識中常見的混淆函數。此外,類型檢查器不會回溯,並且爲了速度而使用不支持回溯的技術來實現。所以它並沒有真正有能力假設使用替代函數;只要它看到它所承諾的'.'。 – dfeuer

4

您希望application operator($) :: (a -> b) -> a -> b而不是功能組成(.) :: (b -> c) -> (a -> b) -> a -> c的點。

modernise s = unwords $ map (\m -> [toUpper (head m)] ++ tail m) (words s) 

這是一樣的

modernise s = unwords (map (\m -> [toUpper (head m)] ++ tail m) (words s)) 
2

「地圖功能的參數太多」;但我給了2個參數(lambda函數和「words」的結果),這是很多參數。

沒錯。在map (\m -> [toUpper (head m)] ++ tail m) (words s)的子表達式中,您給出了map兩個參數,並獲得了一個非函數類型的值爲[String]的值。但是,您將結果視爲函數,因爲(.)的第二個參數必須是函數類型。

每當您嘗試提供一個函數值的地方,編譯器都會提供診斷。有問題的子表達式是函數map的多個應用程序,這就是爲什麼編譯器提出您可能試圖用太多參數提供它的建議。

正如其他人已經說過,您需要($)函數。