在Chiusano和Bjarnason阅读 Scala中的函数编程时,我在第9章Parser Combinators中遇到了以下代码:
trait Parsers[ParseError, Parser[+_]] { self =>
...
def or[A](s1: Parser[A], s2: Parser[A]): Parser[A]
implicit def string(s: String): Parser[String]
implicit def operators[A](p: Parser[A]) = ParserOps[A](p)
implicit def asStringParser[A](a: A)(implicit f: A => Parser[String]):
ParserOps[String] = ParserOps(f(a))
case class ParserOps[A](p: Parser[A]) {
def |[B>:A](p2: Parser[B]): Parser[B] = self.or(p,p2)
def or[B>:A](p2: => Parser[B]): Parser[B] = self.or(p,p2)
}
}
据我所知,如果在编译期间存在类型不兼容或缺少参数,Scala编译器会查找缺少的函数,该函数将非匹配类型转换为所需类型或范围内的变量,并且具有适合的所需类型分别缺少参数。
如果字符串出现在需要Parser[String]
的地方,则应引发上述特征中的字符串函数以将字符串转换为Parser[String]
。
但是,我在理解operators
和asStringParser
功能时遇到了困难。这些是我的问题:
case class
,为什么不能在Parsers特征本身中定义|
或or
函数?asStringParser
到底想要完成的是什么?它的目的是什么?self
?该书说,"使用self来明确消除对特征或方法的引用的歧义,"但这是什么意思?我真的很喜欢这本书,但本章中使用高级语言特定的结构阻碍了我的进步。如果你能向我解释这段代码是如何工作的,那将会很有帮助。我知道我们的目标是让图书馆“更好”。通过|
和or
等运营商使用,但不了解这是如何完成的。
答案 0 :(得分:3)
ParserOps[A]
。您不必明确地将其写出来,因为在这种情况下,它可以自动推断。ParserOps.apply
- 工厂方法。您在构造函数中需要更少的val
,并且您不需要new
关键字来实例化ParserOps
。虽然它不用于模式匹配,所以,你可以用普通的(非case
)类做同样的事情,不重要。|
和or
附加到Parser
,而不强制Parser
继承任何内容。通过这种方式,您可以稍后将Parser
声明为ParserState => Result[A]
,但您仍然可以使用方法|
和or
(即使Function1[ParserState, Result[A]]
没有他们)。您可以将|
和or
直接放在Parsers
中,但之后您必须使用语法
|(a, b)
or(a, b)
而不是更好的
a | b
a or b
没有"真正的运营商"在Scala中,一切都是一种方法。如果你想实现一个行为就好像它是一个中缀运算符的方法,那么你就完全按照书中所做的那样做了。