Вариант монады в скале - PullRequest
5 голосов
/ 26 ноября 2010

как должен работать вариант монады?Я просматриваю scala api и есть пример (я имею в виду второй),

Из-за того, как работает понимание, если из request.getParameter возвращается None, все выражение приводит к None

Но когда я пробую этот код:

 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(""))

, я получаю ошибку компиляции.Как это должно работать?

Ответы [ 3 ]

13 голосов
/ 26 ноября 2010

Вы получаете ошибку компилятора из-за этого

  name <- None

Таким образом, тип None устанавливается на None.type, а переменная name выводится как тип Nothing. (То есть он имел бы этот тип, если бы он действительно существовал, но очевидно, что для понимания он даже не добрался до его создания во время выполнения.) Поэтому не существует метода name.trim, и он не будет компилироваться.

Если бы у вас был request.getParameter("name") в наличии, его тип был бы Option[String], name потенциально мог бы иметь тип String и name.trim скомпилировал бы.

Вы можете обойти это, указав тип None:

  name <- None: Option[String]
5 голосов
/ 27 ноября 2010

Чтобы расширить ответ Кевина, вы можете избежать переноса значений в Some(), используя оператор = вместо оператора <-:

val upper = for {
   name <- None: Option[String] //request.getParameter("name")
   trimmed = name.trim
   upper = trimmed.toUpperCase if trimmed nonEmpty
} yield upper

Фор-понимание будет компилироваться во что-то очень похожее на версию Кевина, но я часто нахожу более понятным явное использование map и filter, чтобы избежать беспорядка (например, дополнительных имен переменных), который ничего не добавляет к семантическому контенту выражения.

3 голосов
/ 26 ноября 2010

Чтобы расширить ответ Дебилски, вам также не нужно явно оборачивать последующие значения в Some(), единственное значение, которое вы на самом деле отображаете, - это оригинальное name.

Лучше было бы использовать операции map и filter напрямую, а не для понимания:

ПРИМЕЧАНИЕ: за кулисами компилятор Scala в любом случае преобразует фор-понимание в комбинацию 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("") )
...