2014-09-03 61 views
2

編譯這是工作無法獲取點免費符號在Haskell

unique :: (a -> Bool) -> [a] -> Bool 
unique p xs = 1 == length (filter p xs) 

但現在我想它的形式:

unique = (== 1) . length . filter 

錯誤消息:

Couldn't match expected type `[a] -> Bool' with actual type `Bool' 
Expected type: b0 -> [a] -> Bool 
    Actual type: b0 -> Bool 
In the first argument of `(.)', namely `(== 1)' 
In the expression: (== 1) . length . filter 

爲什麼這不起作用?

回答

6

這是因爲filter是一個兩參數函數。你可以解決這個獲得使用便捷的操作

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

-- Important to make it the same precedence as (.) 
infixr 9 .: 

unique = ((== 1) . length) .: filter 

如果你看一下在GHCI (length .)類型,你會得到

(length .) :: (a -> [b]) -> a -> Int 

這意味着它需要一個單個參數功能返回一個列表。如果我們看一下filter類型:

filter :: (a -> Bool) -> [a] -> [a] 

這可以被改寫,使其「單參數」作爲

filter :: (a -> Bool) -> ([a] -> [a]) 

這很清楚不a -> [b]排隊!尤其是,編譯器無法弄清楚如何使([a] -> [a])[b]相同,因爲一個是列表上的函數,另一個只是列表。所以這是類型錯誤的來源。


有趣的是,.:運營商可以推廣到函子上工作,而不是:

(.:) :: (Functor f, Functor g) => (a -> b) -> f (g a) -> f (g b) 
(.:) = fmap fmap fmap 
-- Since the first `fmap` is for the (->) r functor, you can also write this 
-- as (.:) = fmap `fmap` fmap === fmap . fmap 

這是什麼好處?假設你有一個Maybe [[Int]],你希望每個子表的總和Just內設置了它的存在:

> let myData = Just [[3, 2, 1], [4], [5, 6]] 
> sum .: myData 
Just [6, 4, 11] 
> length .: myData 
Just [3, 1, 2] 
> sort .: myData 
Just [[1,2,3],[4],[5,6]] 

或者,如果你有一個[Maybe Int]什麼,你想增加每個:

> let myData = [Just 1, Nothing, Just 3] 
> (+1) .: myData 
[Just 2,Nothing,Just 4] 

可能性繼續下去。基本上,它可以讓你在兩個嵌套的函子內映射一個函數,這種結構經常會出現。如果您曾經在Maybe或列表中的元組中有一個列表,或者IO返回了一個字符串或類似的東西,那麼您遇到了可以使用(.:) = fmap fmap fmap的情況。

+2

'unique =(== 1)。:length。:filter'也是可能的。另一方面'(== 1)。長度。:filter ::(Num([a] - > Int),Eq([a] - > Int))=>(a - > Bool) - > Bool'可能會檢測,但是沒用。 – Lambdageek 2014-09-04 22:46:01