Краткий сбор данных во вложенных списках в Scala - PullRequest
0 голосов
/ 10 октября 2018

Я пишу простой интерпретатор в 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).Есть ли способ сделать этот поиск кратким, не расточительным?

Ответы [ 2 ]

0 голосов
/ 10 октября 2018

Вы можете определить специальный экстрактор для извлечения значения 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
  }
}
0 голосов
/ 10 октября 2018

Использование view должно сделать оценку ленивой, а затем вы можете использовать map и filter следующим образом:

def lookup(s: LSymbol): Option[Value] =
  this.frames.view.map(_.find(s)).filter(_.nonEmpty).head

Это однострочный, но, возможно, не такой краткий, каквам может понравиться ...

...