Note that there are some explanatory texts on larger screens.

plurals
  1. POWriting type class instances for nested classes in Scala
    primarykey
    data
    text
    <p>In <a href="https://stackoverflow.com/questions/7699831/turning-a-list-sequence-of-combinator-parsers-into-a-single-one">this recent Stack Overflow question</a>, 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 <code>sequence</code> for applicative functors:</p> <pre><code>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) } </code></pre> <p>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 <code>Applicative</code> instance for <code>Parser</code>, so this code doesn't compile, but that's easy to fix:</p> <pre><code>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: =&gt; A) = success(a) } implicit def ParserFunctor: Functor[Parser] = new Functor[Parser] { def fmap[A, B](p: Parser[A], f: A =&gt; B) = p.map(f) } implicit def ParserBind: Bind[Parser] = new Bind[Parser] { def bind[A, B](p: Parser[A], f: A =&gt; Parser[B]) = p.flatMap(f) } } </code></pre> <p>This works as expected: <code>parser("1 2 3 4 5 6")</code> gives us <code>List(List(1), List(2, 3), List(4, 5, 6))</code>, for example.</p> <p>(I know I could just give an <code>Apply</code> instance, but the <code>Bind</code> instance is more concise.)</p> <p>It would be nice not to have to do this every time we extend <code>Parsers</code>, but I'm not clear on how to get an <code>Applicative</code> instance for <code>Parsers#Parser</code> more generally. The following naive approach of course doesn't work, since we need the instances of <code>Parsers</code> to be the same:</p> <pre><code>implicit def ParserBind: Bind[Parsers#Parser] = new Bind[Parsers#Parser] { def bind[A, B](p: Parsers#Parser[A], f: A =&gt; Parsers#Parser[B]) = p.flatMap(f) } </code></pre> <p>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?</p> <hr> <p>In response to the answers below: I did try the <code>-Ydependent-method-types</code> route, and got this far:</p> <pre><code>implicit def ParserApplicative(g: Parsers): Applicative[g.Parser] = { val f = new Functor[g.Parser] { def fmap[A, B](parser: g.Parser[A], f: A =&gt; B) = parser.map(f) } val b = new Bind[g.Parser] { def bind[A, B](p: g.Parser[A], f: A =&gt; g.Parser[B]) = p.flatMap(f) } val p = new Pure[g.Parser] { def pure[A](a: =&gt; A) = g.success(a) } Applicative.applicative[g.Parser](p, FunctorBindApply[g.Parser](f, b)) } </code></pre> <p>The problem (as <a href="https://stackoverflow.com/users/754787/didierd">didierd</a> points out) is that it's unclear how to get the <code>implicit</code> to kick in. So this approach does work, but you have to add something like the following to your grammar:</p> <pre><code>implicit val applicative = ParserApplicative(this) </code></pre> <p>At that point the mixin approach is obviously much more attractive.</p> <p>(As a side note: I expected to be able to write simply <code>Applicative.applicative[g.Parser]</code> above, but that gives an error saying the compiler can't find an implicit value for the <code>Pure[g.Parser]</code>—even though one is sitting right next to it. So clearly there's something different about the way implicits work for dependent method types.)</p> <hr> <p>Thanks to <a href="https://stackoverflow.com/users/160378/retronym">retronym</a> for pointing out a trick that accomplishes what I want here. I've abstracted the following from <a href="https://github.com/retronym/scalaz7-experimental/commit/aa80e4792799a509c728eecff771ec74518720e7" rel="nofollow noreferrer">his code</a>:</p> <pre><code>implicit def parserMonad[G &lt;: Parsers with Singleton] = new Monad[({ type L[T] = G#Parser[T] })#L] { def pure[A](a: =&gt; 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) =&gt; G#Parser[B]): G#Parser[B] = p.flatMap(f) } </code></pre> <p>If you have this in scope, you get a monad instance for <code>Parser</code> in any object extending <code>Parsers</code>. It's kind of cheating because of the cast, but still pretty neat.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload