Parser DSL and infix operators

Hey! I’m relatively new to Elm and I don’t have a ton of experience with Haskell, either, so forgive my newbiness here, but I’m trying to wrap my head around how the Parser module works. I really like the elegance of the syntax, but it seems a bit magical to me and I feel like if I understood how Elm read the code then it would at least unravel some of the mysteries behind this module.

Specifically, I came across this example in the Parser docs:

succeed identity
  |. keyword "let"
  |. spaces
  |= elmVar
  |. spaces
  |. symbol "="

What I’m curious about is how Elm actually parses this expression. I looked at the source code and noticed that |. and |= are defined as left-associative infix operators, with |. taking higher precedence. I couldn’t find an exact source for this, but I’m also guessing that function calls take the highest precedence. With that in mind, is the following how Elm interprets this? (I realize that if you know the answer already, then the parentheses get in the way, but bear with me here.)

(((succeed identity) |. (keyword "let")) |. spaces) |= ((elmVar |. spaces) |. (symbol "="))

If that’s the case, can you interpret this as something like…?

|= (|. (|. (succeed identity) (keyword "let")) spaces) (|. (|. elmVar spaces) (symbol "="))
1 Like

Indeed, and you can actually add parentheses around operators to use them as functions.

So your parser can be rewritten as

(|=) ((|.) ((|.) (succeed identity) (keyword "let")) spaces) ((|.) ((|.) elmVar spaces) (symbol "=")) 

or using keeper for (|=) and ignorer for (|.) as defined internally:

keeper (ignorer (ignorer (succeed identity) (keyword "let")) spaces) (ignorer (ignorer elmVar spaces) (symbol "=")) 

However as noted in https://github.com/elm/parser/blob/02839df10e462d8423c91917271f4b6f8d2f284d/src/Parser/Advanced.elm#L61, the different precedence values are only to slightly reduce the amount
of recursion in pipelines, so understanding them is not required to understand how the parser pipelines work.

So the expression with the same precedence values would lead to the same parser functionally:

(ignorer (ignorer (keeper (ignorer (ignorer (succeed identity) (keyword "let")) spaces) elmVar) spaces) (symbol "="))

or

((|.) ((|.) ((|=) ((|.) ((|.) (succeed identity) (keyword "let")) spaces) elmVar) spaces) (symbol "="))
3 Likes

Ah, interesting, I didn’t know that! Thanks so much.

1 Like

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.