简洁的collectFirst超过scala中的嵌套列表
Concise collectFirst over nested lists in scala
我正在用 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)
中是多余的。有没有办法以一种不浪费的方式以某种方式简洁地执行此查找?
使用 view
应该使评估变得懒惰,然后你可以像这样使用 map
和 filter
:
def lookup(s: LSymbol): Option[Value] =
this.frames.view.map(_.find(s)).filter(_.nonEmpty).head
这是单行的,但可能没有您喜欢的那么简洁...
您可以定义一个特殊用途的提取器来提取 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 来简化提取器的构建:
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
}
}
我正在用 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)
中是多余的。有没有办法以一种不浪费的方式以某种方式简洁地执行此查找?
使用 view
应该使评估变得懒惰,然后你可以像这样使用 map
和 filter
:
def lookup(s: LSymbol): Option[Value] =
this.frames.view.map(_.find(s)).filter(_.nonEmpty).head
这是单行的,但可能没有您喜欢的那么简洁...
您可以定义一个特殊用途的提取器来提取 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 来简化提取器的构建:
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
}
}