如何写“否则容易”的慵懒,可变参数版本
-
22-07-2019 - |
题
是否有可能从写一个orElse
广义Option
方法采用可变数目的参数?即,代替,:
lazy val o1 = { println("foo"); None }
lazy val o2 = { println("bar"); Some("bar") }
lazy val o3 = { println("baz"); Some("baz") }
// ...
o1 orElse o2 orElse o3 // orElse ...
您可以使用:
orElse(o1, o2, o3) //, ...
解决方案
按照 Scala语言规范(4.6函数声明和定义)不能定义可变参数按姓名参数:
ParamType ::= Type
| ‘=>’ Type
| Type ‘*’
scala> def orElse(x : (=> String)*)
<console>:1: error: no by-name parameter type allowed here
def orElse(x : (=> String)*)
您可以取代懒惰ARG与功能和隐式类型转换:
def orElse[T](x : (()=> Option[T])*) : Option[T] =
if(x.isEmpty) None else x.first.apply.orElse(orElse((x drop 1) :_*))
implicit def anyToFun0[T](t : => T) : (() => T) = () => t
orElse(o1, o2, o3)
其他提示
我发现问题有点晚:)。一种可能性是用辅助函数来包装=> A
成辅助类在一起以简化其制作:
import scala.language.implicitConversions
class Helper[+A](value: => A) extends Function0[A] {
override def apply(): A = value;
}
object Helper {
def unapply[A](h: Helper[A]): Option[A] = Some(h());
}
implicit def toHelper[A](body: => A) = new Helper(body);
,则不需要抽出器,它只是允许在辅助容易匹配。然后,我们可以写
def orElse[A](xs: Helper[Option[A]]*): Option[A] =
xs.collectFirst[A]({
case Helper(Some(r)) => r;
})
lazy val o1 = { println("foo"); None }
lazy val o2 = { println("bar"); Some("bar") }
lazy val o3 = { println("baz"); Some("baz") }
orElse(o1, o2, o3) //, ...
这仅仅是一个简化的解决方案,更现实的一个将是
def orElse[A](x: Option[A], xs: Helper[Option[A]]*): Option[A]
使用更有效的实现。
有已经是一类在相似于Scalaz Helper
,称为Name
与实施Need
其确保所述主体被评估最多一次。因此,与Scalaz,它可以实现为
import scala.language.implicitConversions
import scalaz._
import scalaz.Scalaz._
implicit def toNeed[A](body: => A): Name[A] = Need(body);
def orElse[A](xs: Name[Option[A]]*): Option[A] =
xs.collectFirst[A]({
case Name(Some(r)) => r;
})
lazy val o1 = { println("foo"); None }
lazy val o2 = { println("bar"); Some("bar") }
lazy val o3 = { println("baz"); Some("baz") }
orElse(o1, o2, o3) //, ...
不隶属于 StackOverflow