Frage

Ist es möglich, eine generali orElse Methode von Option zu schreiben, die eine variable Anzahl von Argumenten nimmt? Das heißt, statt:

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 ...

Sie können verwendet werden:

orElse(o1, o2, o3) //, ...
War es hilfreich?

Lösung

Nach dem Die Scala Language Specification (4.6 Funktionsdeklarationen und Definitionen) Sie können nicht definieren varargs by-Name-Parameter:

ParamType ::= Type
| ‘=>’ Type
| Type ‘*’

scala> def orElse(x : (=> String)*)
<console>:1: error: no by-name parameter type allowed here
       def orElse(x : (=> String)*)

Sie könnten die faulen arg mit Funktion und eine implizite Typumwandlung ersetzen:

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)

Andere Tipps

Ich fand die Frage ein bisschen spät :). Eine Möglichkeit ist => A in eine Hilfsklasse zu wickeln zusammen mit einer Hilfsfunktion ihre Gründung zu vereinfachen:

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);

Der Extraktor nicht erforderlich ist, es erlaubt nur leicht Matching auf dem Helfer. Dann können wir schreiben

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) //, ...

Dies ist nur eine vereinfachte Lösung, eine realistischere würde man sein

def orElse[A](x: Option[A], xs: Helper[Option[A]]*): Option[A]

mit einer effizienteren Umsetzung.


Es ist schon eine Klasse ähnlich in Scalaz Helper, genannt Name mit Implementierung Need, die sicherstellt, dass der Körper höchstens einmal ausgewertet wird. Also mit Scalaz, könnte es als implementiert werden

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) //, ...
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top