Home > Software engineering >  Why can't I use Data.Function.(&) in the same expression as Control.Arrow.(>>>)?
Why can't I use Data.Function.(&) in the same expression as Control.Arrow.(>>>)?

Time:11-09

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.

  • Related