scala - ¿Por qué la opción no tiene un método de plegado?
map fold (4)
Me pregunto por qué scala.Option
no tiene un método fold
como este definido:
fold(ifSome: A => B , ifNone: => B)
equivalente a
map(ifSome).getOrElse(ifNone)
¿No hay nada mejor que usar map
+ getOrElse
?
Como lo mencionó Debilski, puedes usar Scalaz''s OptionW.cata
o fold
. Como Jason comentó, los parámetros nombrados hacen que se vea bien:
opt.fold { ifSome = _ + 1, ifNone = 0 }
Ahora, si el valor que desea en el caso None
es mzero
para algún Monoid[M]
y tiene una función f: A => M
para el caso Some
, puede hacer esto:
opt foldMap f
Asi que,
opt map (_ + 1) getOrElse 0
se convierte
opt foldMap (_ + 1)
Personalmente, creo que Option
debería tener un método de apply
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.
Finalmente se agregó en Scala 2.10 , con el fold[B](ifEmpty: => B)(f: A => B): B
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 únicamente en el argumento ifEmpty
, que en la práctica a menudo es más limitado. Por ejemplo (una versión correcta ya está en la biblioteca estándar, esto es solo para demostración)
def toList[A](x: Option[A]) = x.fold(Nil)(_ :: Nil)
Scala Nil.type
B
es Nil.type
lugar de la List[A]
deseada List[A]
y se queja de que f
no devuelve Nil.type
. En cambio, necesitas uno de
x.fold[List[A]](Nil)(_ :: Nil)
x.fold(Nil: List[A])(_ :: Nil)
Esto hace que el fold
no sea completamente equivalente al match
correspondiente.
Personalmente encuentro métodos como cata
que toman dos cierres ya que los argumentos a menudo lo exageran. ¿Realmente ganas en legibilidad sobre map
+ getOrElse
? Piense en un recién llegado a su código: ¿qué harán de
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, yo diría que ninguno de los dos es preferible a los buenos
opt match {
case Some(x) => x + 1
case None => 0
}
Como siempre, hay un límite donde la abstracción adicional no le da beneficios y se vuelve contraproducente.
Tu puedes hacer:
opt foldLeft (els) ((x, y) => fun(x))
o
(els /: opt) ((x,y) => fun(x))
(Ambas soluciones evaluarán els
por valor, lo que podría no ser lo que usted desea. Gracias a Rex Kerr por señalarlo).
Editar:
Pero lo que realmente quieres es la catamorphism de Scalaz (básicamente un fold
que no solo maneja el valor Some
sino que también mapea la parte None
, que es lo que describes)
opt.cata(fun, els)
definido como (donde el value
es el value
la opción pimped)
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 expresarlo. Hay muchos casos en que basta con un map
simple: getOrElse
, especialmente cuando se trata de encadenar potencialmente muchos map
. (Aunque también podría encadenar la fun
con la composición de la función, por supuesto, depende de si desea enfocarse en la composición de la función o la transformación del valor).