Warum hat keine Option eine Faltmethode?
-
26-10-2019 - |
Frage
ich wundere mich warum scala.Option
hat keine Methode fold
So definiert:
fold(ifSome: A => B , ifNone: => B)
gleichwertig
map(ifSome).getOrElse(ifNone)
Gibt es nicht besser als zu verwenden map
+ getOrElse
?
Lösung
Du kannst tun:
opt foldLeft (els) ((x, y) => fun(x))
oder
(els /: opt) ((x,y) => fun(x))
(Beide Lösungen werden bewertet els
nach Wert, was nicht das ist, was Sie wollen. Dank an Rex Kerr zum Hinweis darauf.)
Bearbeiten:
Aber was Sie wirklich wollen, ist Scalaz's Katamorphismus cata
(Grundsätzlich a fold
was nicht nur das behandelt Some
Wert, aber auch die None
Teil, was Sie beschrieben haben)
opt.cata(fun, els)
definiert als (wo value
ist der pimped Optionswert)
def cata[X](some: A => X, none: => X): X = value match {
case None => none
case Some(a) => some(a)
}
das entspricht zu opt.map(some).getOrElse(none)
.
Obwohl ich bemerken sollte, dass Sie Cata nur dann verwenden sollten, wenn es die „natürlichere“ Art ist, es auszudrücken. Es gibt viele Fälle, in denen einfach map
–getOrElse
reicht vor, insbesondere wenn es darum geht, viele viel zu verketten map
s. (Obwohl Sie auch die ketten können fun
s mit Funktionszusammensetzung natürlich - es hängt davon ab, ob Sie sich auf die Funktionszusammensetzung oder die Werttransformation konzentrieren möchten.)
Andere Tipps
Ich persönlich finde Methoden wie cata
Das dauert zwei Schließungen, da Argumente es oft übertreiben. Gewinnen Sie wirklich in der Lesbarkeit map
+ getOrElse
? Denken Sie an einen Neuankömmling Ihres Code: Woraus werden sie machen
opt cata { x => x + 1, 0 }
Denken Sie wirklich, dass dies klarer ist als
opt map { x => x + 1 } getOrElse 0
Tatsächlich würde ich argumentieren, dass keiner gegenüber dem guten Alten vorzuziehen ist
opt match {
case Some(x) => x + 1
case None => 0
}
Wie immer gibt es eine Grenze, bei der zusätzliche Abstraktion keine Vorteile bietet und kontraproduktiv wird.
Es wurde schließlich hinzugefügt in Scala 2.10, mit der Unterschrift fold[B](ifEmpty: => B)(f: A => B): B
.
Leider hat dies eine gemeinsame negative Folge: B
wird für Anrufe abgeleitet, die nur auf dem basieren ifEmpty
Argument, das in der Praxis oft enger ist. EG (eine korrekte Version befindet sich bereits in der Standardbibliothek. Dies dient nur zur Demonstration)
def toList[A](x: Option[A]) = x.fold(Nil)(_ :: Nil)
Scala wird schließen B
sein Nil.type
statt gewünscht List[A]
und beschweren sich über f
nicht zurückkehren Nil.type
. Stattdessen brauchen Sie einen von
x.fold[List[A]](Nil)(_ :: Nil)
x.fold(Nil: List[A])(_ :: Nil)
Das macht fold
Nicht ganz entsprechend entsprechend match
.
Wie von Debilski erwähnt, können Sie Scalaz's verwenden OptionW.cata
oder fold
. Wie Jason kommentierte, machen benannte Parameter dies gut:
opt.fold { ifSome = _ + 1, ifNone = 0 }
Nun, wenn der Wert, den Sie in der gewünscht haben None
Fall ist mzero
für einige Monoid[M]
Und Sie haben eine Funktion f: A => M
für die Some
Fall können Sie dies tun:
opt foldMap f
So,
opt map (_ + 1) getOrElse 0
wird
opt foldMap (_ + 1)
Ich persönlich denke Option
sollte eine haben apply
Methode, die der Katamorphismus wäre. Auf diese Weise könnten Sie das einfach tun:
opt { _ + 1, 0 }
oder
opt { some = _ + 1, none = 0 }
In der Tat wäre dies schön für alle algebraischen Datenstrukturen.