wxw
wxw

Reputation: 123

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?

Upvotes: 1

Views: 81

Answers (2)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476534

No, operators have a lower precedence than functions, so that means that your expression:

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

Is equal to:

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

or in a more canonical form:

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

Now (.) is defined as:

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

So in this context, f = reverse, and g = ((drop 1) (reverse xs)), so we have basically written:

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

or we can move the x parameter to the head of the function:

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

So you are missing the x here in your rewrite. We can rewrite the code to:

inita = (reverse .) . drop 1 . reverse

since:

   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)

Upvotes: 3

leftaroundabout
leftaroundabout

Reputation: 120711

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

Upvotes: 4

Related Questions