mónada opción en Scala
-
28-09-2019 - |
Pregunta
¿Cómo se entiende que mónada opción de trabajo? Estoy navegar por la Scala API y hay un ejemplo (me refiero a la segunda),
Debido a la forma de las obras de comprensión, si ninguno se volvió de request.getParameter, toda la expresión da como resultado Ninguno
Pero cuando intento este código:
val upper = for {
name <- None //request.getParameter("name")
trimmed <- Some(name.trim)
upper <- Some(trimmed.toUpperCase) if trimmed.length != 0
} yield upper
println(upper.getOrElse(""))
me sale un error de compilación. ¿Cómo se supone que funciona?
Solución
Se obtiene un error de compilación debido a esto
name <- None
De esta manera, el tipo de None
se establece en None.type
y la name
variable se infiere a ser de tipo Nothing
. (Es decir, que tendría este tipo si en realidad existía, pero, obviamente, la de comprensión ni siquiera llegar a crear en tiempo de ejecución.) Por lo tanto no existe name.trim
método y que no se compilará.
Si tuviera request.getParameter("name")
disponible, su tipo sería Option[String]
, name
tendría potencialmente tipo String
y name.trim
se compilará.
Se puede evitar esto especificando el tipo de None
:
name <- None: Option[String]
Otros consejos
Para ampliar la respuesta de Kevin, se puede evitar valores de envoltura en Some()
usando el operador =
en lugar del operador <-
:
val upper = for {
name <- None: Option[String] //request.getParameter("name")
trimmed = name.trim
upper = trimmed.toUpperCase if trimmed nonEmpty
} yield upper
El-comprensión de compilará a algo muy similar a la versión de Kevin, pero a menudo resultará más clara a utilizar map
y filter
explícitamente al desorden de evitar (por ejemplo, los nombres de variables adicionales) que no añaden nada al contenido semántico de la expresión.
Para ampliar la respuesta de Debilski, también no es necesario para envolver de manera explícita los valores subsiguientes en Some()
, el único valor que realmente se aplica la relación es la más name
originales.
Un mejor enfoque sería ser el uso de las operaciones map
y filter
directamente en lugar de una para-comprensión:
NOTA: detrás de las escenas, el compilador Scala convertirá una para la comprensión de una combinación de mapa / flatMap / filtro de todos modos, por lo que este enfoque no será menos eficiente que una para-comprensión, y puede muy bien ser más eficiente
def clean(x:Option[String]) = x map { _.trim.toUpperCase } filterNot { _.isEmpty }
val param = None : Option[String] // request.getParameter("name")
println( clean(param).getOrElse("") )