Scala:对集合(策略模式)的懒惰评估

时间:2013-08-14 13:14:49

标签: scala lazy-evaluation

我有这种结构:

if(condition1)
  lengthyOperation1
else if(condition2)
  lengthyOperation2
else if(condition3)
  lengthyOperation3
...
else
  lastLengthyOperation

我想以下列方式表达:

lazy val seq = Seq(
  condition1 -> lengthyOperation1,
  condition2 -> lengthyOperation2,
  condition3 -> lengthyOperation3,
  ...
  true -> lastLengthyOperation
)

seq.find(_._1).match { case(_, v) => v }

问题是最后一行的评估在到达“seq”时执行所有冗长的操作。我该怎么做才能让长时间的操作只在需要时执行?

注意:条件不可能是同一表达式的模式匹配(即我不能使用单个匹配语句)

编辑:我应该使用Stream吗?

2 个答案:

答案 0 :(得分:0)

我猜您的意思是Seq,而不是Map

您可以在此使用Seq代替if序列,但我认为它不具备可读性。

您应该在getOrElse之后使用find。假设每个lengthyOperationN都是一个函数:

seq.find(_._1).map{_._2}.getOrElse(lastLengthyOperation).apply()

答案 1 :(得分:0)

你的方法的问题是你在错误的地方懒惰。当你宣布

lazy val seq = Seq(
  condition1 -> lengthyOperation1,
  ...
)

然后一旦你触摸seq,整个序列都会进行所有冗长的操作,无论你触摸哪一个。序列的元素是严格的。

您可以使用Stream执行您想要的操作,但我想使用专为此目的设计的Option更容易。让我们在选项上声明一个帮助器隐式函数。如果在Some上调用它,则它不会执行任何操作。如果在None上调用它,它会检查一个条件,如果它满足,则返回Some(result)

implicit class IfOption[A](opt: Option[A]) {
  def ?>[B >: A](condition: Boolean, result: => B): Option[B] =
    opt.orElse(if (condition) Some(result) else None);
}

现在我们可以做像

这样的事情
println(
    None
      ?> (1 != 1, "A")
      ?> (2 == 2, "B")
      ?> (3 == 2, "C")
)

其中打印表达式的类型为Option[String]并打印Some(B)

println(
    None
      ?> (1 != 1, "Yes")
      ?> (2 != 2, "No")
      ?> (3 != 2, "heck")
      getOrElse ("ah")
)

其中类型只是“String”。