在阅读Chiusano和Bjarnason在Scala中的函数式编程时,我在第9章Parser Combinator中遇到了以下代码:
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]的位置,则应调用上述特性中的string函数将字符串转换为Parser[String]。
但是,我很难理解operators和asStringParser函数。以下是我要问的问题:
case class,为什么不能在解析器特征本身中定义|或or函数?asStringParser到底想要达到什么目的?它在这里的目的是什么?self?这本书说,“使用自我来明确地消除对特征的或方法的引用”,但这意味着什么呢?我真的很喜欢这本书,但是在本章中使用高级语言结构阻碍了我的进步。如果您能向我解释这段代码是如何工作的,这将有很大的帮助。我知道目标是通过|和or这样的运算符来使库“更好”使用,但不明白这是如何做到的。
发布于 2018-04-13 15:15:02
ParserOps[A]。您不必显式地写出它,因为在这种情况下,可以自动推断它。ParserOps.apply-factory方法。构造函数中需要更少的val,并且不需要new关键字来实例化ParserOps。但是,它并不用于模式匹配,因此,您可以使用一个普通的(非case)类做同样的事情,这并不重要。|和or附加到Parser,而不强制Parser继承任何东西。这样,以后可以声明Parser是类似于ParserState => Result[A]的东西,但是仍然有|和or可用的方法(尽管Function1[ParserState, Result[A]]没有它们)。|和or直接放在Parsers中,但是必须使用以下语法
(a,b)或(a,b)
而不是更好的
A、b、a或bScala中没有“真正的运算符”,一切都是一种方法。如果您想要实现一个行为像infix操作符一样行为的方法,那么您可以做书中所做的事情。
https://stackoverflow.com/questions/49816716
复制相似问题