scala map fold scala-option

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