【问题标题】:Can't get point free notation to compile in Haskell无法在 Haskell 中编译无点符号
【发布时间】:2014-09-03 15:07:42
【问题描述】:

这是有效的

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

为什么这不起作用?

【问题讨论】:

    标签: haskell pointfree function-composition


    【解决方案1】:

    这是因为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 的情况。

    【讨论】:

    • unique = (== 1) .: length .: filter 也是可能的。另一方面,(== 1) . length .: filter :: (Num ([a] -> Int), Eq ([a] -> Int)) => (a -> Bool) -> Bool 可能会进行类型检查,但没有用。
    猜你喜欢
    • 1970-01-01
    • 2014-11-29
    • 2013-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多