6

Reading through this informative, well-written article on Parser Combinators, I see this code:

class DisParser[+A](left: Parser[A], right: Parser[A]) extends Parser[A] {
  def apply(s: Stream[Character]) = left(s) match {
    case res: Success => res
    case _: Failure => right(s)
  }
}

When I try to compile this code, I get:

Parser.scala:19: error: class Success takes type parameters
    case res: Success => res
              ^
one error found

Given the signature of Parser:

case class Success[+A](value: A, rem: Stream[Character]) extends Result[A]

How can I change the case res: Success => res line to give Success a proper type parameter?

Kevin Meredith
  • 41,036
  • 63
  • 209
  • 384

2 Answers2

6

Which Success are you using? This one (Success from Parsers package) or this one (Success from util)? Both take type parameters, so you'll need to put it as

res @ Success(_, _) =>

otherwise you'll have to deal with the erasure warning.

wheaties
  • 35,646
  • 15
  • 94
  • 131
  • I'm using the `Success` defined in that article. Also, I tried your `case Success(_, _) => ...` example, but got: `error: '=>' expected but '(' found.` – Kevin Meredith Nov 25 '13 at 18:08
  • @KevinMeredith can you post your updated code? What I wrote should be what you replace `res: Success =>` with – wheaties Nov 25 '13 at 18:33
  • Oh, my mistake for not including `@`. I don't know what that symbol means. Yes, I no longer get the previous compile-time error when using your code. However, I got a new compile-time error: `scala:26: error: covariant type A occurs in contravariant position in type Parser[A] of value that def |(that: Parser[A]) = new DisParser(this, that) ^` – Kevin Meredith Nov 25 '13 at 19:19
  • @KevinMeredith You should make that method `def |[AA >: A](that: Parser[AA])` Read up on covariant types in Scala. It's eye opening. – wheaties Nov 25 '13 at 22:50
  • Thanks, @wheaties. Your solution & the commented change fixed my problem. I've watched Odersky's FP in Scala lecture on Covariance twice, and read this post (http://stackoverflow.com/questions/663254/scala-covariance-contravariance-question) multiple times, but I haven't grokked covariance yet. A few more times should do the trick :) – Kevin Meredith Nov 26 '13 at 04:37
  • @KevinMeredith If you like Scala... would you be open to joining a company that does Scala full-time? I love me some Scala. I see your email on your github. – wheaties Nov 26 '13 at 14:46
2

Your parser should return a value of type Result[A], as its type definition says (basically a parser is a function from character streams to a parse result).:

trait Parser[+A] extends (Stream[Character]=>Result[A])

So you have two options:

case res@Success(_,_) => res

Is a match against the variant of the returned case class.

case res:Success[_] => res.asInstanceOf[Success[A]]

Is a match against the returned type (using an instanceof operation). That's why you have to cast (you cannot match against a type parameter without a typetag value, since the JVM does type erasure).

Both are valid in your case, in the first case, you omitted the type parameter (that is what your original error was about). In your attempt to follow @wheaties advice, you made a syntax error somewhere in your code, but this is indeed the best way to go here.

choeger
  • 3,562
  • 20
  • 33