Вариант монады в Scala
-
28-09-2019 - |
Вопрос
Как предназначено для работы варианта монада? Я просматриваю Scala API и есть пример (я имею в виду второй),
Из-за того, как для понимания работает, если никто не возвращается из запроса .getParameter, все выражение приводит к ним
Но когда я пробую этот код:
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(""))
Я получаю ошибку компиляции. Как это должно работать?
Решение
Вы получаете ошибку компилятора из-за этого
name <- None
Таким образом, тип None
установлен в None.type
и переменная name
выводится, чтобы иметь тип Nothing
. Отказ (То есть у него будет такой тип, если он фактически существует, но, очевидно, то для понимания даже не может создавать его во время выполнения.) Поэтому нет метода name.trim
существует, и это не скомпилируется.
Если у тебя есть request.getParameter("name")
доступно, его тип будет Option[String]
, name
потенциально будет иметь тип String
и name.trim
будет компилировать.
Вы можете работать вокруг этого, указав тип None
:
name <- None: Option[String]
Другие советы
Чтобы расширить ответ Кевина, вы можете избежать оборотных значений в Some()
Используя =
оператор вместо <-
Оператор:
val upper = for {
name <- None: Option[String] //request.getParameter("name")
trimmed = name.trim
upper = trimmed.toUpperCase if trimmed nonEmpty
} yield upper
Для понимания будет сознавать что-то очень похожее на версию Кевина, но я часто считаю более понятными для использования map
и filter
Явно, чтобы избежать беспорядка (например, дополнительные имена переменного), которые ничего не добавляют к семантическому содержанию выражения.
Чтобы расширить ответ Дебильского, вам также не нужно явно обернуть последующие значения в Some()
, единственное значение, которое вы на самом деле отображаете, является оригиналом name
.
Лучший подход будет использовать map
и filter
Операции напрямую вместо понимания:
Примечание. За кулисами Scala Compiler преобразует средство для понимания в комбинацию MAP / Flatmap / Filter в любом случае, поэтому этот подход никогда не будет менее эффективным, чем для понимания, и вполне может быть более эффективным
def clean(x:Option[String]) = x map { _.trim.toUpperCase } filterNot { _.isEmpty }
val param = None : Option[String] // request.getParameter("name")
println( clean(param).getOrElse("") )