关于 haskell 组成的错误

An error about haskell composition

我写了一个函数:

inita xs = reverse . (drop 1) (reverse xs)

我认为等于:

inita xs = reverse (  (drop 1) (reverse xs)  )

但我有错误:

 Couldn't match expected type ‘a -> [a1]’ with actual type ‘[a2]’
    Relevant bindings include
      xs :: [a2] (bound at ch2.hs:1:7)
      init1 :: [a2] -> a -> [a1] (bound at ch2.hs:1:1)
    Possible cause: ‘drop’ is applied to too many arguments
    In the second argument of ‘(.)’, namely ‘(drop 1) (reverse xs)’
    In the expression: reverse . (drop 1) (reverse xs)
Failed, modules loaded: none.

那么那个组合表达式有什么问题?

不,运算符的优先级低于函数,因此这意味着您的表达式:

inita xs =  reverse  .  (drop 1) (reverse xs)

等于:

inita xs = (reverse) . ((drop 1) (reverse xs))

或更规范的形式:

inita xs = (.) (reverse) ((drop 1) (reverse xs))

现在(.)定义为:

(.) :: (b -> c) -> (a -> b) -> a -> c
(.) f g x = f (g x)

所以在这个上下文中,f = reverse,和g = ((drop 1) (reverse xs)),所以我们基本上写成:

inita xs = \x -> reverse ((drop 1) (reverse xs) x)

或者我们可以将x参数移动到函数的头部:

inita xs x = reverse ((drop 1) (reverse xs) x)

所以你在重写中遗漏了 x。我们可以将代码重写为:

inita = (reverse .) . drop 1 . reverse

自从:

   inita xs = (.) reverse ((drop 1) (reverse xs))
-> inita xs = ((.) reverse) ((drop 1) (reverse xs))
-> inita xs = ((.) reverse) ((.) (drop 1) reverse xs)
-> inita = ((.) reverse) . ((.) (drop 1) reverse)
-> inita = ((.) reverse) . (drop 1 . reverse)
-> inita = ((.) reverse) . drop 1 . reverse
-> inita = (reverse .) . (drop 1 . reverse)

reverse ( (drop 1) (reverse xs) ) 等于 (reverse . drop 1) (reverse xs)。但这不是 reverse . (drop 1) (reverse xs) 被解析的内容,因为中缀运算符的优先级低于函数应用程序。出于这个原因,它实际上被解析为 reverse . ((drop 1) (reverse xs)),但这没有任何意义(即不进行类型检查),因为 (drop 1) (reverse xs) 不是函数而是列表。

编写此类函数的首选方法是

inita xs = reverse . drop 1 $ reverse xs

在这里,我用 low-precedence $ 运算符替换了 high-precedence 普通函数应用程序(它除了应用函数外什么都不做,但由于优先级较低,它其实这个没错composition-function).

但实际上,您不需要它,因为您只在最后传入 xs 一次。因此,您不妨也将 reverse 设为合成链的一部分:

inita xs = reverse . drop 1 . reverse $ xs

...可以简单地将 η 简化为

inita = reverse . drop 1 . reverse