Search code examples
scalaparser-generator

Implementation of ~> and <~ parser combinators operators


Scala's source explains these operators:

~> is a parser combinator for sequential composition which keeps only the right result.

<~ is a parser combinator for sequential composition which keeps only the left result

I wrote the following two classes. Note that Daniel Spiewak's excellent article on this topic helped me very much to begin to understand Parser Combinators.

~>

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

and <~:

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

Here's the test:

val s4 = Stream[Character]('f', 'o', 'o', 'b', 'a', 'r', 'b', 'u', 'z', 'z')
val krp = new KeepRightParser("foo", "bar")
println("~> test: " + krp(s4))

val klp = new KeepLeftParser("foo", "bar")
println("<~ test: " + klp(s4))

with output:

~> test: Success(bar,Stream(b, ?))
<~ test: Success(foo,Stream(b, a, r, b, ?))

As I understand, the second stream shows more than its head since bar needed to be read for parsing the second half of the sequence.

Is this correct?


Solution

  • Yes you are correct. Stream's toString isn't immutable as you can verify in the REPL:

    scala> val s = Stream(1,2,3,4,5,6,7,8)
    s: scala.collection.immutable.Stream[Int] = Stream(1, ?)
    
    scala> s(3)
    res5: Int = 4
    
    scala> s
    res6: scala.collection.immutable.Stream[Int] = Stream(1, 2, 3, 4, ?)