Can';无法在Haskell中编译无点符号

Can';无法在Haskell中编译无点符号,haskell,pointfree,function-composition,Haskell,Pointfree,Function Composition,这是有效的 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] ->

这是有效的

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

这为什么不起作用?

这是因为
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 :: (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
这有什么用?假设您有一个
可能[[Int]]
,并且您想要
中每个子列表的总和,只要它存在:

> 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]]
或者,如果您有一个
[可能是Int]
,并且您想增加每一个:

> let myData = [Just 1, Nothing, Just 3]
> (+1) .: myData
[Just 2,Nothing,Just 4]
可能性不断。基本上,它允许你在两个嵌套的函子中映射一个函数,这种结构经常出现。如果您曾经在
中有一个列表,或者列表中有一个元组,或者
IO
返回一个字符串,或者诸如此类的东西,那么您会遇到一种情况,您可以使用
(.:)=fmap-fmap
unique=(==1)。:长度:filter
。另一方面,
(==1)。长度:filter::(Num([a]->Int),Eq([a]->Int))=>(a->Bool)->Bool
可以进行类型检查,但没有用处。
> let myData = [Just 1, Nothing, Just 3]
> (+1) .: myData
[Just 2,Nothing,Just 4]