zig*_*tar 4 scala monad-transformers scalaz
我有一个monadic类型Exp,我想构建一个解析为这样的值的解析器.以下代码有效,但是我能做些更好/更酷的事情吗?
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)
Run Code Online (Sandbox Code Playgroud)
我听说过monad变形金刚,但仍然有点害怕Scalaz 7的奇怪的导入系统.有人可以回答是否
ExpMonad 的Scala组合器解析器.首先是简单的部分 - "怪异"的导入系统:
import scalaz._, Scalaz._
Run Code Online (Sandbox Code Playgroud)
就这样.这将永远有效(当然,除非是名称冲突,但这对任何库来说都是可能的并且易于解决),没有人会因为没有使用新的单点菜单导入而瞧不起你,这主要是关于文档的.
monad变换器的基本模式是你有一个WhateverT[F[_], ...]类型类,它有一个名为runWhateverT(或只是run)的方法返回一个F[Whatever[...]].
在这种情况下,看起来你想要最终得到一个Parser[Exp],这表明你需要自己的ExpT[F[_]]变压器.我不会从有关如何实现它的细节开始(当然,这将取决于你的monad的语义),但是会给出一个使用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)
}
Run Code Online (Sandbox Code Playgroud)
在这里查看我的问题,讨论我们为什么需要这implicit val monad = ...条线.
它的工作原理如下:
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
Run Code Online (Sandbox Code Playgroud)
请注意,oddNumber.run这将给我们一个Parser[Option[Int]]将解析一串数字并返回a Some(i)(如果它们代表奇数)或a None(如果它们是偶数).
oddNumber.run然而,在这种情况下,我们实际上并没有打电话- 事实上我们使用monad变换器意味着我们可以在一次理解中oddNumber使用提升的Parser动作(在literal(...)这里)进行组合for.
这里的语法是丑陋的,我们失去了漂亮的~组合子和隐式转换从String到Parser[String],例如,但如果我们想,我们可以很容易地举起写这些东西的版本.