在最近的Stack Overflow问题中,作者想要将某种类型的解析器列表更改为返回该类型列表的解析器。我们可以使用Scalaz的应用函子
在这里,我们将返回整数列表的三个解析器转换为返回整数列表的列表的解析器。不幸的是,Scalaz没有为Parser提供Applicative实例,因此这段代码无法编译,但很容易修复:
这段代码按预期工作:
(我知道我可以提供一个
不需要每次扩展
作为对下面答案的回应:我确实尝试了
问题在于(正如didierd所指出的那样),不清楚如何让
如果你有这个范围,你可以在任何扩展
sequence
来实现这一点:import scala.util.parsing.combinator._
import scalaz._
import Scalaz._
object parser extends RegexParsers {
val parsers = List(1, 2, 3).map(repN(_, """\d+""".r))
def apply(s: String) = parseAll(parsers.sequence, s)
}
在这里,我们将返回整数列表的三个解析器转换为返回整数列表的列表的解析器。不幸的是,Scalaz没有为Parser提供Applicative实例,因此这段代码无法编译,但很容易修复:
import scala.util.parsing.combinator._
import scalaz._
import Scalaz._
object parser extends RegexParsers {
val parsers = List(1, 2, 3).map(repN(_, """\d+""".r))
def apply(s: String) = parseAll(parsers.sequence, s)
implicit def ParserPure: Pure[Parser] = new Pure[Parser] {
def pure[A](a: => A) = success(a)
}
implicit def ParserFunctor: Functor[Parser] = new Functor[Parser] {
def fmap[A, B](p: Parser[A], f: A => B) = p.map(f)
}
implicit def ParserBind: Bind[Parser] = new Bind[Parser] {
def bind[A, B](p: Parser[A], f: A => Parser[B]) = p.flatMap(f)
}
}
这段代码按预期工作:
parser("1 2 3 4 5 6")
返回 List(List(1), List(2, 3), List(4, 5, 6))
。(我知道我可以提供一个
Apply
实例,但Bind
实例更加简洁。)不需要每次扩展
Parsers
时都这样做会很好,但我不清楚如何更普遍地为Parsers#Parser
获得一个Applicative
实例。下面的天真方法当然行不通,因为我们需要Parsers
的实例相同:implicit def ParserBind: Bind[Parsers#Parser] = new Bind[Parsers#Parser] {
def bind[A, B](p: Parsers#Parser[A], f: A => Parsers#Parser[B]) = p.flatMap(f)
}
我很清楚这应该是可能的,但我对Scala的类型系统还不够熟悉,不知道如何处理。是否有什么简单的方法我忽略了?
作为对下面答案的回应:我确实尝试了
-Ydependent-method-types
的方法,进展到了这一步:implicit def ParserApplicative(g: Parsers): Applicative[g.Parser] = {
val f = new Functor[g.Parser] {
def fmap[A, B](parser: g.Parser[A], f: A => B) = parser.map(f)
}
val b = new Bind[g.Parser] {
def bind[A, B](p: g.Parser[A], f: A => g.Parser[B]) = p.flatMap(f)
}
val p = new Pure[g.Parser] {
def pure[A](a: => A) = g.success(a)
}
Applicative.applicative[g.Parser](p, FunctorBindApply[g.Parser](f, b))
}
问题在于(正如didierd所指出的那样),不清楚如何让
implicit
起作用。因此,这种方法确实有效,但您需要向语法中添加类似以下内容的内容:implicit val applicative = ParserApplicative(this)
在那个时候,混合方法显然更具吸引力。
(顺便说一句:我希望能够简单地编写Applicative.applicative [g.Parser]
,但会出现错误,表示编译器找不到Pure [g.Parser]
的隐式值——尽管它就在旁边。因此,对于相关方法类型,隐式工作方式明显有所不同。)
感谢 retronym指出了一个技巧,可以实现我在这里想要的功能。以下内容是从他的代码中抽象出来的:
implicit def parserMonad[G <: Parsers with Singleton] =
new Monad[({ type L[T] = G#Parser[T] })#L] {
def pure[A](a: => A): G#Parser[A] = {
object dummy extends Parsers
dummy.success(a).asInstanceOf[G#Parser[A]]
}
def bind[A, B](p: G#Parser[A], f: (A) => G#Parser[B]): G#Parser[B] =
p.flatMap(f)
}
如果你有这个范围,你可以在任何扩展
Parsers
对象中获得Parser
的monad实例。这有点像作弊,因为涉及到转换,但仍然很棒。
implicit val M: Monad[Parser] = parserMonad(testParser)
。你认为这不可能吗? - Travis BrownParsers
,才能调用success
。你可以将parser
本身设为隐式以将其提供给parserMonad
,但这听起来并不是一个好主意。 - retronymasInstanceOf
,你实际上可以完成这个任务:https://github.com/retronym/scalaz7-experimental/commit/aa80e4792799a509c728eecff771ec74518720e7 - retronym