In this recent Stack Overflow question, the author wanted to change a list of parsers of some type into a parser that returns lists of that type. We can imagine doing this with Scalaz's sequence
for applicative functors:
import scala.util.parsing.combinator._
import scalaz._
import Scalaz._
object parser extends RegexParsers {
val parsers = List(1, 2, 3).map(repN(_, """\d+""".r))
def apply(s: String) = parseAll(parsers.sequence, s)
}
Here we take a list of three parsers that return lists of integers and turn it into a parser that returns lists of lists of integers. Unfortunately Scalaz doesn't provide an Applicative
instance for Parser
, so this code doesn't compile, but that's easy to fix:
import scala.util.parsing.combinator._
import scalaz._
import Scalaz._
object parser extends RegexParsers {
val parsers = List(1, 2, 3).map(repN(_, """\d+""".r))
def apply(s: String) = parseAll(parsers.sequence, s)
implicit def ParserPure: Pure[Parser] = new Pure[Parser] {
def pure[A](a: => A) = success(a)
}
implicit def ParserFunctor: Functor[Parser] = new Functor[Parser] {
def fmap[A, B](p: Parser[A], f: A => B) = p.map(f)
}
implicit def ParserBind: Bind[Parser] = new Bind[Parser] {
def bind[A, B](p: Parser[A], f: A => Parser[B]) = p.flatMap(f)
}
}
This works as expected: parser("1 2 3 4 5 6")
gives us List(List(1), List(2, 3), List(4, 5, 6))
, for example.
(I know I could just give an Apply
instance, but the Bind
instance is more concise.)
It would be nice not to have to do this every time we extend Parsers
, but I'm not clear on how to get an Applicative
instance for Parsers#Parser
more generally. The following naive approach of course doesn't work, since we need the instances of Parsers
to be the same:
implicit def ParserBind: Bind[Parsers#Parser] = new Bind[Parsers#Parser] {
def bind[A, B](p: Parsers#Parser[A], f: A => Parsers#Parser[B]) = p.flatMap(f)
}
It's pretty clear to me that this should be possible, but I'm not comfortable enough with Scala's type system to know how to go about it. Is there something simple that I'm missing?
In response to the answers below: I did try the -Ydependent-method-types
route, and got this far:
implicit def ParserApplicative(g: Parsers): Applicative[g.Parser] = {
val f = new Functor[g.Parser] {
def fmap[A, B](parser: g.Parser[A], f: A => B) = parser.map(f)
}
val b = new Bind[g.Parser] {
def bind[A, B](p: g.Parser[A], f: A => g.Parser[B]) = p.flatMap(f)
}
val p = new Pure[g.Parser] {
def pure[A](a: => A) = g.success(a)
}
Applicative.applicative[g.Parser](p, FunctorBindApply[g.Parser](f, b))
}
The problem (as didierd points out) is that it's unclear how to get the implicit
to kick in. So this approach does work, but you have to add something like the following to your grammar:
implicit val applicative = ParserApplicative(this)
At that point the mixin approach is obviously much more attractive.
(As a side note: I expected to be able to write simply Applicative.applicative[g.Parser]
above, but that gives an error saying the compiler can't find an implicit value for the Pure[g.Parser]
—even though one is sitting right next to it. So clearly there's something different about the way implicits work for dependent method types.)
Thanks to retronym for pointing out a trick that accomplishes what I want here. I've abstracted the following from his code:
implicit def parserMonad[G <: Parsers with Singleton] =
new Monad[({ type L[T] = G#Parser[T] })#L] {
def pure[A](a: => A): G#Parser[A] = {
object dummy extends Parsers
dummy.success(a).asInstanceOf[G#Parser[A]]
}
def bind[A, B](p: G#Parser[A], f: (A) => G#Parser[B]): G#Parser[B] =
p.flatMap(f)
}
If you have this in scope, you get a monad instance for Parser
in any object extending Parsers
. It's kind of cheating because of the cast, but still pretty neat.