Reputation: 123
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
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
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