Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Probably the most general solution would be to rewrite Scala's parser library to accommodate monadic computations while parsing (like you partly did), but that would be quite a laborious task.</p> <p>I suggest a solution using <a href="http://scalaz.github.com/scalaz/" rel="noreferrer">ScalaZ</a>'s <a href="http://scalaz.github.com/scalaz/scalaz-2.9.1-6.0.4/doc/index.html#scalaz.State" rel="noreferrer">State</a> where each of our result isn't a value of type <code>Parse[X]</code>, but a value of type <code>Parse[State[Stream[Char],X]]</code> (aliased as <code>ParserS[X]</code>). So the overall parsed result isn't a value, but a monadic state value, which is then run on some <code>Stream[Char]</code>. This is almost a monad transformer, but we have to do lifting/unlifting manually. It makes the code a bit uglier, as we need to lift values sometimes or use <code>map</code>/<code>flatMap</code> on several places, but I believe it's still reasonable.</p> <pre><code>import scala.util.parsing.combinator._ import scalaz._ import Scalaz._ import Traverse._ object ParenParser extends RegexParsers with States { type S[X] = State[Stream[Char],X]; type ParserS[X] = Parser[S[X]]; // Haskell's `return` for States def toState[S,X](x: X): State[S,X] = gets(_ =&gt; x) // Haskell's `mapM` for State def mapM[S,X](l: List[State[S,X]]): State[S,List[X]] = l.traverse[({type L[Y] = State[S,Y]})#L,X](identity _); // ................................................. // Read the next character from the stream inside the state // and update the state to the stream's tail. def next: S[Char] = state(s =&gt; (s.tail, s.head)); def paren: ParserS[List[(Char, String)]] = "(" ~&gt; contents &lt;~ ")" ^^ (_ flatMap { case (s, m) =&gt; next map (v =&gt; (v -&gt; s) :: m) }) def contents: ParserS[(String, List[(Char, String)])] = digits | parens; def digits: ParserS[(String, List[(Char, String)])] = "\\d+".r ^^ (_ -&gt; Nil) ^^ (toState _) def parens: ParserS[(String, List[(Char, String)])] = rep1(paren) ^^ (mapM _) ^^ (_.map( ps =&gt; ps.map(_.head._1).mkString -&gt; ps.flatten )) def parse(s: String): ParseResult[S[Map[Char,String]]] = parseAll(paren, s).map(_.map(_.toMap)) def parse(s: String, names: Stream[Char]): ParseResult[Map[Char,String]] = parse(s).map(_ ! names); } object ParenParserTest extends App { { println(ParenParser.parse("((617)((0)(32)))", Stream('a' to 'z': _*))); } } </code></pre> <hr> <p><strong>Note:</strong> I believe that your approach with <code>StateT[Parser, Stream[Char], _]</code> isn't conceptually correct. The type says that we're constructing a parser given some state (a stream of names). So it would be possible that given different streams we get different parsers. This is not what we want to do. We only want that the <em>result</em> of parsing depends on the names, not the <em>whole parser</em>. In this way <code>Parser[State[Stream[Char],_]]</code> seems to be more appropriate (Haskell's Parsec takes a similar approach, the state/monad is inside the parser).</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.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      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