Syntax error with "infixl" and "infixr" operators

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

fmap (myRecord & _2 . someField .~) double

      

And this doesn't work completely:

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 is infixr

and infixl

? How can I rewrite the function to fix it?

+3


source to share


2 answers


You just cannot mix the operators of this commit. A fix in Haskell is just operator precedence, like your "Please forgive my dear Aunt Sally" (if you are American, this is probably what you learned) for remembering which order to apply operations to, that is, in parentheses. exponential, multiplication, division, addition, subtraction. Here the operator .~

has a higher right associative priority than the left associative low operator priority &

. The real problem is mixing the right and left associative operators, the compiler doesn't know which order to apply them to!

Instead, you can rewrite it as two sections of a statement put together

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

      

To give the compiler an explicit grouping or you can use a prefix set

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

like

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

      

+4


source


This is a somewhat odd limitation on how operators can be used in sections.

Basically, when you have a statement section, for example (e1 & e2 .~)

, there are two ways you can imagine to defuse it with non- partitioned notation. One is to turn the operator into a prefix position:

(.~) (e1 & e2)

      

(If the operator was in front, you would also need to add a flip

.)

Another way is to turn it into a lambda expression:



\x -> e1 & e2 .~ x

      

These two ways of thinking sections should give the same result. The problem is that, like here, there is another operator &

with a lower reliability / priority than the partition operator. Since this means the lambda expression is expressed as

\x -> e1 & (e2 .~ x)

      

In other words, a lambda expression is definitely not equivalent to simply moving the operator around and keeping the rest as a unified expression.

While the Haskell designers could have chosen to interpret a section in one of two ways, they instead chose to disallow sections where the two interpretations do not match and make their mistakes. Perhaps because, as I understand it, the interpretation of the lambda expression is more intuitive for humans, whereas the operator movement is easier to implement in the parser / compiler.

You can always use the lambda expression explicitly, or create your own silent version like @bheklilr.

+2


source







All Articles