我正在Scala中编写一个简单的解释器。
此解释器存储本质上为List[List[(Symbol, Value)]]
的环境:
case class Env(frames: List[Frame]) {
def lookup(s: LSymbol): Option[Value] = ??? // help
}
case class Frame(associations: List[(LSymbol, Value)]){
def find(s: LSymbol): Option[Value] = {
this.associations.collectFirst {case (s1, v) if s1 == s => v}
}
}
从本质上讲,我想依次搜索每个帧以找到匹配的符号。尽管为此编写一个小的尾部递归搜索功能非常简单,但感觉可以通过collectFirst
单行代码更高效,更通用地完成某些事情,就像这样:
def lookup(s: LSymbol): Option[Value] =
this.frames.collectFirst{
case frame if frame.find(s).nonEmpty => frame.find(s).get
}
但是,这在第二个frame.find(s)
中是多余的。有没有办法以一种不浪费的方式简洁地进行此查找?
答案 0 :(得分:2)
使用view
应该会使评估变得懒惰,然后可以像这样使用map
和filter
:
def lookup(s: LSymbol): Option[Value] =
this.frames.view.map(_.find(s)).filter(_.nonEmpty).head
这是单线的,但可能不像您想的那么简洁...
答案 1 :(得分:2)
您可以定义一个专用提取器来提取frame.find(s)
值。这样,您还将摆脱nonEmpty
/ get
的调用,因为模式匹配已经为您做到了:
def lookup(s: LSymbol): Option[Value] = {
object FindS {
def unapply(frame: Frame): Option[Value] = frame.find(s)
}
this.frames.collectFirst {
case FindS(value) => value
}
}
如果您经常执行这样的操作,您甚至可能想要定义一个帮助器类以简化提取器的构造:
class Extractor[T, X](f: T => Option[X]) {
def unapply(arg: T): Option[X] = f(arg)
}
def lookup(s: LSymbol): Option[Value] = {
object FindS extends Extractor((frame: Frame) => frame.find(s))
this.frames.collectFirst {
case FindS(value) => value
}
}