Parser combinators in Scala bookParsing: Taking unstructured data as input and processing it into a structured output. Such as the JSON format shown as example.
An algebra is a collection of functions operating over some data type(s), along with a set of laws specifying the relationship between these functions. This is an approach we have used before, and will continue to use with parsing.
The parser in this example works on strings for simplicity.
Initially we start with defining an interface. We purposefully ignore the fact that we do not know anything about the class Parser or ParseError.
Parser && run methoddef char(c : Char): Parser[Char]
extension [A](p: Parser[A]) def run(input: String): Either[ParseError, A]
traittrait Parsers[ParseError, Parser[+_]]:
def char(c: Char): Parser[Char]
extension [A](p: Parser[A]
def run(input: String): Either[ParseError, A]
def |(p2: Parser[A]): Parser[A] = p.or(p2)
Wrapping it in a trait simplifies the process of creating a new Parser as it inherits a lot of the fundamental functionality that is inherit to the trait of being a Parser. In this case it is inherit that our Parser takes a string as input and produces Either a ParseError that is yet to be defined, or it returns a value with the type A.
By combining general use parsers we can reuse already made functionality into more specific parsers.
The infix def makes or usable as an operator, such as p or p2. However, this is also defined by the normal | operator as shown above. We use this for the rest of the example. This is one example of combining two parsers.