scala中的选项monad

时间:2010-11-26 19:21:10

标签: scala monads scala-option

如何使用Option monad?我正在浏览scala api并且有一个例子(我的意思是第二个),

  

由于理解的工作原理,如果从request.getParameter返回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 个答案:

答案 0 :(得分:13)

由于此原因,您收到编译器错误

  name <- None

这样,None的类型设置为None.type,变量name被推断为类型Nothing。 (也就是说,如果它实际存在,它会有这种类型,但很明显,for comprehension甚至不能在运行时创建它。)因此,没有方法name.trim存在且不会编译。

如果您有request.getParameter("name")可用,则其类型为Option[String]name可能会有String类型,name.trim会被编译。

您可以通过指定None

的类型来解决此问题
  name <- None: Option[String]

答案 1 :(得分:5)

要扩展凯文的答案,您可以使用Some()运算符而不是=运算符来避免在<-中包装值:

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

for-comprehension将编译为与Kevin的版本非常相似的东西,但我经常发现更明确地使用mapfilter来明确地避免混乱(例如额外的变量名称)表达式的语义内容。

答案 2 :(得分:3)

要扩展Debilski的答案,您也不需要在Some()中明确包装后续值,您实际映射的唯一值是原始name

更好的方法是直接使用mapfilter操作,而不是for-comprehension:

注意:在幕后,Scala编译器无论如何都会将for-comprehension转换为map / flatMap / filter的组合,因此这种方法永远不会比for-comprehension效率低,而且很可能是更有效率

def clean(x:Option[String]) = x map { _.trim.toUpperCase } filterNot { _.isEmpty }

val param = None : Option[String] // request.getParameter("name")
println( clean(param).getOrElse("") )