Monad wrapping in a parser - I need Monad Transformers and how to do it?

I have a monadic type Exp , and I want to build a parser that parses that value. The following code works, but is there something nicer / colder than I can do?

 def grid(x: Int, y: Int): Problem = ??? def expInt: Parser[Exp[Int]] = ??? def grid: Parser[Exp[Problem]] = for{ ex ~ _ ~ ey <- "grid(" ~> expInt ~ "," ~ expInt <~ ")" } yield for{ x <- ex y <- ey } yield grid(x,y) 

I heard about monad transformers, but still a little scared of the Scalaz 7 wierd import system. Can anyone answer

  • I can use monad transformers and
  • What it will look like in principle, using Scalaz 7 for the Scala combiner parser wrapping my own Exp Monad.
+4
source share
1 answer

First for the easy part is the β€œstrange” import system:

 import scalaz._, Scalaz._ 

It's all. This will always work (of course, to prevent name collisions, but this is possible with any library and is easily resolved), and no one is going to look down on you to not use the new import a la carte, which is mainly related to documentation.

The basic template for monad transformers is that you have a class like WhateverT[F[_], ...] that has a method called runWhateverT (or just run ) that returns F[Whatever[...]] .

In this case, it looks like you want to get a Parser[Exp] , which assumes that you need your own ExpT[F[_]] transformer ExpT[F[_]] . I will not start with details on how to implement this (which, of course, will depend on the semantics of your monad), but will give an example using Scalaz OptionT :

 import scala.util.parsing.combinator._ import scalaz._, Scalaz._ object MyParser extends RegexParsers { implicit val monad = parserMonad(this) def oddNumber: OptionT[Parser, Int] = OptionT.optionT( "\\d+".r ^^ (_.toInt) ^^ (i => (i % 2 != 0) option i) ) def pairOfOdds: OptionT[Parser, (Int, Int)] = for { _ <- literal("(").liftM[OptionT] x <- oddNumber _ <- literal(",").liftM[OptionT] y <- oddNumber _ <- literal(")").liftM[OptionT] } yield (x, y) def apply(s: String) = parse(pairOfOdds.run, s) } 

See my question here for a discussion of why we need the string implicit val monad = ...

It works as follows:

 scala> MyParser("(13, 43)") res0: MyParser.ParseResult[Option[(Int, Int)]] = [1.9] parsed: Some((13,43)) scala> MyParser("(13, 42)") res1: MyParser.ParseResult[Option[(Int, Int)]] = [1.8] parsed: None 

Note that oddNumber.run will give us Parser[Option[Int]] , which will parse the string of digits and return either Some(i) (if they represent an odd number) or None (if they are even).

In fact, we will not call oddNumber.run , but in this case, the fact that we are using a monad transformer means that we can create oddNumber with the canceled actions Parser ( literal(...) here) in one sense for .

The syntax here is ugly: we lose the pretty compilers ~ and implicit conversions from String to Parser[String] , but we could easily write canceled versions of these things if we wanted to.

+6
source

Source: https://habr.com/ru/post/1487610/


All Articles