1

要从 GHCi 中的列表中删除最后一项,我可以反转列表,取出尾部,然后再次反转它。例如,

reverse(tail(reverse([1,2,3,4])))

由于那里有很多括号,我想我会改变它以使用函数组合。但是,当我尝试此操作时,出现以下错误。

Prelude> reverse . tail. reverse [1,2,3,4]

<interactive>:2:17:
    Couldn't match expected type `a0 -> [a1]' with actual type `[a2]'
    In the return type of a call of `reverse'
    Probable cause: `reverse' is applied to too many arguments
    In the second argument of `(.)', namely `reverse [1, 2, 3, 4]'
    In the second argument of `(.)', namely
      `tail . reverse [1, 2, 3, 4]'

我认为这意味着它不喜欢 compose reverse [1,2,3,4],所以我尝试在它周围加上括号,但它给了我同样的错误。

Prelude> reverse . tail. (reverse [1,2,3,4])

<interactive>:3:18:
    Couldn't match expected type `a0 -> [a1]' with actual type `[a2]'
    In the return type of a call of `reverse'
    Probable cause: `reverse' is applied to too many arguments
    In the second argument of `(.)', namely `(reverse [1, 2, 3, 4])'
    In the second argument of `(.)', namely
      `tail . (reverse [1, 2, 3, 4])'

但是,如果我执行以下操作,它可以正常工作。

Prelude> let f = reverse . tail . reverse
Prelude> f [1,2,3,4]
[1,2,3]

是什么导致了这个错误,为什么 let 绑定阻止了这个错误的发生?

4

2 回答 2

8

当您看到 type of 时,.您会注意到它希望其两个操作数都是函数(具有合适的类型,以便可以组合它们)

Prelude> :i (.)
(.) :: (b -> c) -> (a -> b) -> a -> c   -- Defined in `GHC.Base'
infixr 9 .

现在函数应用程序的优先级高于任何中缀运算符,所以

Prelude> reverse . tail . reverse [1,2,3,4]

变成

Prelude> reverse . tail . (reverse [1,2,3,4])

当您尝试应用组合时,它的类型错误。为了使组合正确,您必须明确赋予组合比函数应用更高的优先级,您可以通过提供显式括号来做到这一点。

Prelude> (reverse . tail . reverse) [1,2,3,4]

此解决方案有效,但haskellers 讨厌使用括号。这是另一个运算符$,它可以将您保存在这些地方,并使您的代码比使用括号更具可读性。当你看到类型$

Prelude> :i ($)
($) :: (a -> b) -> a -> b       -- Defined in `GHC.Base'
infixr 0 $

您可以清楚地看到它的优先级 (0) 小于 compostion (9) 的优先级,这给了您想要的效果。您可以降低最后一个函数应用的优先级或将函数组合替换为$.

Prelude> reverse . tail . reverse $ [1,2,3,4]
Prelude> reverse . tail $ reverse [1,2,3,4]
Prelude> reverse $ tail $ reverse [1,2,3,4]

这很好,因为第一个操作数$是一个函数,而其他只是一个正确类型的值。

于 2013-01-09T13:05:58.807 回答
4

let函数组合的情况下.,然后给出一个列表作为函数组合结果的参数:

(reverse . tail . reverse) [1,2,3,4]

在另一种情况下,列表作为参数给出,reverse并尝试将其结果与其他一些函数组合:

reverse . tail . (reverse [1,2,3,4])

由于返回的反向列表reverse [1,2,3,4]不是函数,因此将其用作 for 的参数.会导致类型错误。

于 2013-01-09T13:02:59.430 回答