Why can't I use Data.Function.(&)
in the same expression as Control.Arrow.(>>>)
?
I'm learning Haskell after spending a lot of time in F#, and I find that right to left notation is making it tough to understand longer pipelines. (I know it's not idiomatic)
I'd read that &
and >>>
were the Haskell equivalent to F#'s |>
and >>
. However, this fails:
[someList] & take 5 >>> sum
with a "precedence error":
Prelude Data.Function Control.Arrow> [1:10] & take 5 >>> sum <interactive>:4:1: error: Precedence parsing error cannot mix `&' [infixl 1] and `>>>' [infixr 1] in the same infix expression
while
sum . take 5 $ [someList]
obviously doesn't.
CodePudding user response:
&
has the right precedence to be chained on its own:
[1..10] & take 5 & sum
You don't need >>>
for anything here, and &
and >>>
weren't co-designed so their precedence doesn't really fit for this use case.
CodePudding user response:
It's not "precedence error", it's "precedence parsing error" (emphasis mine).
If we try it in GHCi, > :i &
replies with infixl 1 &
, while > :i >>>
replies with infixr 1 >>>
.
So one (&
) parenthesizes on the left (infixl
) and the other (>>>
) on the right (infixr
).
The one with the higher precedence would win, but these two have the same precedence (1
). And that's what the error message is telling us (a bit ineptly):
Precedence parsing error
cannot mix `&' [infixl 1] and `>>>' [infixr 1] in the same infix expression
means, because they have the same precedence, the parsing of these left- and right- associating infix operators mixed together in this expression is ambiguous, and hence impossible.
So you end up having to use explicit parentheses for this expression to parse properly:
[someValue] & (take 5 >>> sum)
By the way, [someValue]
is already a list. Because you use sum
its one element's type must be in Num
(someValue :: Num a => a
, [someValue] :: Num a => [a]
).
But if you rather already have someList
with several numerical values in it (someList :: Num a => [a]
), you just write
someList & (take 5 >>> sum)
because [someList]
is a list with a single value in it, which happens to be a list of numbers (presumably). So with [someList]
the expression wouldn't work anyway:
> [5] & (take 5 >>> sum)
5
> [[3,4,5]] & (take 5 >>> sum)
<interactive>:431:1:
No instance for (Num [t0]) arising from a use of `it'
In a stmt of an interactive GHCi command: print it
Another way to make it parse, with explicit parentheses on the left, is
(someList &) $ take 5 >>> sum
So the parens are closer together and the whole expression is potentially more readable, if you have long chain of expressions connected with >>>
on the right.