haskelloperator-precedenceinfix-operatorparsing-error

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.(>>>)?

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.


Solution

  • 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.