Conclusions

At this point you should have quite a rich interface that looks something like the below:

sealed trait Parser[A] {
  def map[B](f: A => B): Parser[B]
  def product[B](that: Parser[B]): Parser[(A, B)]
  def flatMap[B](f: A => Parser[B]): Parser[B]
  def orElse(that: => Parser[A]): Parser[A]
  def and(that: Parser[A])(implicit m: Semigroup[A]): Parser[A]
  def repeat(implicit m: Monoid[A]): Parser[A]

  def parse(input: String): Result[A]
}
object Parser {
  def string(value: String): Parser[String]
  def pure[A](value: A): Parser[A]
  def fail[A]: Parser[A]
  def pass[A](implicit m: Monoid): Parser[A]
}

In addition, at lot of methods will be available via the type class instances you have created.

There are two big lessons here:

Let's now do something interesting with our parser library, which will show the power of what we've done.

Parsing Expressions→