First off, apologies for length of this question.
I’m having a problem writing parser functions, and it’s exposed a limitation in my understanding of how they work. So, first order, I’d appreciate any help resolving this specific problem. Second order though, any insight into how to think about parser operation more generally would be much appreciated.
Specific Problem
I need to handle attribute declarations, for which there are two variants:
name: Type
name: Type = initialValue
I followed the pattern in this post to come up with the following:
type alias Attribute =
{ name : String
, type_ : String
, value : Maybe String
}
attributeParser : Parser Attribute
attributeParser =
Parser.succeed identity
|= parseLowerCaseName
|. Parser.spaces
|. Parser.symbol ":"
|. Parser.spaces
|= parseUpperCaseName
|> Parser.andThen attributeInitialValueParser
attributeInitialValueParser : String -> String -> Parser Attribute
attributeInitialValueParser name type_ =
Parser.oneOf
[ Parser.succeed (Attribute name type_)
|. Parser.spaces
|. Parser.symbol "="
|. Parser.spaces
|= (Parser.map Just parseValue)
, Parser.succeed (Attribute name type_ Nothing)
]
That doesn’t type check. Intuitively, I think it’s because attributeParser
is pushing 2 values into the pipe (the parsed name & type), but (1) that’s not compatible with Parser.succeed identity
and (2) I’m not convinced the type signature for attributeInitialValueParser
is correct. Perhaps it should take a tuple (String, String)
instead of two separate params?
Any help on that appreciated. Thanks.
General Problem
Hitting this highlighted I don’t understand the parsing mechanism as well as I thought I did. I read through the source, but it’s quite abstract and I’ll admit was a bit of a challenge for an elm newbie. So I don’t feel that much better placed. Intuitively, I understand that the pipeline functions (notably |=
& |.
) facilitate combination. When run, the input string is passed to each Parser function. Those functions do one or both of the following:
- Consume characters from the input stream
- Add parsed elements to the “output stream” (recognising this isn’t really a stream).
However I don’t yet have a good mental model for how to think about this more formally. For example: the compiler error on the code above says:
The 1st argument to `andThen` is not what I expect:
101| |> Parser.andThen attributeInitialValueParser
^^^^^^^^^^^^^^^^^^^^^^^^^^^
This `attributeInitialValueParser` value is a:
String -> Parser b
But `andThen` needs the 1st argument to be:
String -> Parser Attribute
But the type signature for attributeInitialValueParser
is String -> String -> Parser Attribute
.
This is already quite long so I’ll stop here. Any insight appreciated.
Thanks.