Search code examples
haskellsyntaxoperatorsoperator-precedenceinfix-notation

Syntax error with "infixl" and "infixr" operators


I want to update a record using lens with a value parsed by attoparsec.

fmap (myRecord & _2 . someField .~) double

And it totally doesn't work:

Iddq3.hs:99:48:
    The operator ‘.~’ [infixr 4] of a section
        must have lower precedence than that of the operand,
          namely ‘&’ [infixl 1]
        in the section: ‘myRecord & _2 . someField .~’

What does this error mean? What are infixr and infixl? How can I rewrite the function to correct it?


Solution

  • You just can't mix operators of that fixity. Fixity in Haskell is just operator precedence, just like your "Please Excuse My Dear Aunt Sally" (if you're American, this is probably what you learned) for remembering what order to apply operations in, i.e. Parentheses, Exponent, Multiplication, Division, Addition, Subtraction. Here, the .~ operator is said to have a higher right associative precedence than the left associative low precedence of the & operator. The real problem comes from mixing the right and left associative operators, the compiler doesn't know what order to apply them in!

    Instead, you can re-formulate it as two operator sections composed together

    fmap ((myRecord &) . (_2 . someField .~)) double
    

    So that you give the compiler an explicit grouping, or you can use the prefix set function for a cleaner look

    fmap (\v -> set (_2 . someField) v myRecord) double
    

    Or if you want to get rid of the lambda (my preference is to leave it alone), you can use flip as

    fmap (flip (set (_2 . someField)) myRecord) double