Search code examples
haskellcomposition

An error about haskell composition


I wrote a function:

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

I thought it equals:

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

But I had errors:

 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.

So what's wrong with that composition expression?


Solution

  • reverse ( (drop 1) (reverse xs) ) is equal to (reverse . drop 1) (reverse xs). But that's not what reverse . (drop 1) (reverse xs) is parsed as, because infix operators have lower precedence than function application. For this reason, what it's actually parsed as is instead reverse . ((drop 1) (reverse xs)), but that doesn't make any sense (i.e. doesn't typecheck), because (drop 1) (reverse xs) is not a function but a list.

    The preferred way to write such a function is

    inita xs = reverse . drop 1 $ reverse xs
    

    Here, I've replaced the high-precedence plain function application with the low-precedence $ operator (which does nothing else but apply a function, but due to the low precedence it's actually this right composition-function).

    Actually though, you don't need that, because you only pass in xs once at the end. So you might as well make reverse part of the composition chain too:

    inita xs = reverse . drop 1 . reverse $ xs
    

    ...which can simply be η-reduced to

    inita = reverse . drop 1 . reverse