¿Por qué la opción no tiene un método de pliegue?
-
26-10-2019 - |
Pregunta
me pregunto porque scala.Option
no tiene un método fold
Como esto definido:
fold(ifSome: A => B , ifNone: => B)
equivalente a
map(ifSome).getOrElse(ifNone)
¿No hay mejor que usar map
+ getOrElse
?
Solución
Tu puedes hacer:
opt foldLeft (els) ((x, y) => fun(x))
o
(els /: opt) ((x,y) => fun(x))
(Ambas soluciones evaluarán els
por valor, que podría no ser lo que quieres. Gracias a Rex kerr por señalarlo).
Editar:
Pero lo que realmente quieres es Scalaz's catamorfismo cata
(básicamente un fold
que no solo maneja el Some
valor pero también mapea el None
parte, que es lo que describiste)
opt.cata(fun, els)
definido como (donde value
es el valor de la opción con proxenetismo)
def cata[X](some: A => X, none: => X): X = value match {
case None => none
case Some(a) => some(a)
}
que es equivalente a opt.map(some).getOrElse(none)
.
Aunque debo comentar que solo debes usar CATA cuando es la forma "más natural" de expresarla. Hay muchos casos en los que un simple map
–getOrElse
Suficiente, especialmente cuando implica potencialmente encadenar muchos map
s. (Aunque también podrías encadenar el fun
S con la composición de la función, por supuesto, depende de si desea centrarse en la composición de la función o la transformación del valor).
Otros consejos
Personalmente encuentro métodos como cata
que toman dos cierres como argumentos a menudo lo exageran. ¿Realmente ganas en legibilidad? map
+ getOrElse
? Piense en un recién llegado a su código: ¿Qué harán con
opt cata { x => x + 1, 0 }
¿De verdad crees que esto es más claro que
opt map { x => x + 1 } getOrElse 0
De hecho, diría que ninguno es preferible sobre el buen viejo
opt match {
case Some(x) => x + 1
case None => 0
}
Como siempre, hay un límite en el que la abstracción adicional no le brinda beneficios y se vuelve contraproducente.
Finalmente fue agregado En Scala 2.10, con la firma fold[B](ifEmpty: => B)(f: A => B): B
.
Desafortunadamente, esto tiene una consecuencia negativa común: B
se infiere para las llamadas basadas solo en el ifEmpty
argumento, que en la práctica es a menudo más estrecho. Por ejemplo (una versión correcta ya está en la biblioteca estándar, esto es solo para la demostración)
def toList[A](x: Option[A]) = x.fold(Nil)(_ :: Nil)
Scala inferirá B
ser - estar Nil.type
en lugar de deseado List[A]
y quejarse de f
No regresar Nil.type
. En cambio, necesitas uno de
x.fold[List[A]](Nil)(_ :: Nil)
x.fold(Nil: List[A])(_ :: Nil)
Esto hace fold
no del todo equivalente a la correspondiente match
.
Como se menciona por debilski, puedes usar Scalaz's OptionW.cata
o fold
. Como comentó Jason, los parámetros nombrados hacen que esto se vea bien:
opt.fold { ifSome = _ + 1, ifNone = 0 }
Ahora, si el valor que desea en el None
el caso es mzero
para algunos Monoid[M]
Y tienes una función f: A => M
Para el Some
Caso, puede hacer esto:
opt foldMap f
Asi que,
opt map (_ + 1) getOrElse 0
convertirse en
opt foldMap (_ + 1)
Personalmente pienso Option
debería tener un apply
Método que sería el catamorfismo. De esa manera podrías hacer esto:
opt { _ + 1, 0 }
o
opt { some = _ + 1, none = 0 }
De hecho, sería bueno tener esto para todas las estructuras de datos algebraicos.