Pregunta ¿Por qué la opción no tiene un método de plegado?


me pregunto porque 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?


35
2018-03-16 15:57


origen


Respuestas:


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 para 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 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 donde un simple map-getOrElse basta, especialmente cuando implica potencialmente encadenar un montón de maps. (Aunque también podría encadenar funs 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).


25
2018-03-16 16:18



Personalmente encuentro métodos como cata eso toma 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.


66
2018-03-16 22:31



Finalmente fue agregado en Scala 2.10con la firma fold[B](ifEmpty: => B)(f: A => B): B.

Desafortunadamente, esto tiene una consecuencia negativa común: B se infiere para llamadas basadas solo en el ifEmpty argumento, que en la práctica a menudo es más limitado. P.ej. (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 inferirá B ser Nil.type en lugar de deseado List[A] y se quejan de f no regresando Nil.type. En cambio, necesitas uno de

 x.fold[List[A]](Nil)(_ :: Nil)
 x.fold(Nil: List[A])(_ :: Nil)

Esto hace fold no completamente equivalente a la correspondiente match.


41
2018-02-02 14:22



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 None caso es mzero para algunos Monoid[M] y tienes una función f: A => M Para el Some caso, puedes hacer esto:

opt foldMap f

Asi que,

opt map (_ + 1) getOrElse 0

se convierte

opt foldMap (_ + 1)

Personalmente pienso Option debe 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.


19
2018-03-16 23:05