题
我想知道为什么 scala.Option
没有方法 fold
像这样的定义:
fold(ifSome: A => B , ifNone: => B)
相当于
map(ifSome).getOrElse(ifNone)
没有比使用更好的 map
+ getOrElse
?
解决方案
你可以做:
opt foldLeft (els) ((x, y) => fun(x))
或者
(els /: opt) ((x,y) => fun(x))
(两种解决方案都将评估 els
按价值,这可能不是您想要的。谢谢 雷克斯·克尔(Rex Kerr) 指向它。)
编辑:
但是您真正想要的是Scalaz的 ca态 cata
(基本上是 fold
不仅可以处理 Some
价值,但也映射 None
部分,这是您描述的)
opt.cata(fun, els)
定义为(哪里 value
是PIMPED选项值)
def cata[X](some: A => X, none: => X): X = value match {
case None => none
case Some(a) => some(a)
}
等同于 opt.map(some).getOrElse(none)
.
尽管我应该指出,您只能在表达“更自然”的方式时使用CATA。在很多情况下,一个简单 map
–getOrElse
足够,尤其是在涉及潜在链接大量的时候 map
s。 (尽管您也可以连锁 fun
当然,具有功能组成的s - 取决于您是否要专注于功能组成还是值转换。)
其他提示
我个人找到了类似的方法 cata
随着论点经常过分,这两个封闭。你真的会赢得可读性吗 map
+ getOrElse
?想到您的代码的新来者:他们会做什么
opt cata { x => x + 1, 0 }
你真的认为这比
opt map { x => x + 1 } getOrElse 0
实际上,我会说,这两个都不比旧的旧
opt match {
case Some(x) => x + 1
case None => 0
}
与往常一样,额外的抽象不会给您带来好处并适得其反。
终于添加了 在Scala 2.10中, ,带签名 fold[B](ifEmpty: => B)(f: A => B): B
.
不幸的是,这有一个共同的负面后果: B
仅根据基于 ifEmpty
争论,实际上通常更狭窄。例如(标准库中已经有正确的版本,这仅用于演示)
def toList[A](x: Option[A]) = x.fold(Nil)(_ :: Nil)
Scala将推断 B
成为 Nil.type
而不是想要的 List[A]
并抱怨 f
不返回 Nil.type
. 。相反,您需要一个
x.fold[List[A]](Nil)(_ :: Nil)
x.fold(Nil: List[A])(_ :: Nil)
这使得 fold
不等于相应 match
.
如Debilski所述,您可以使用Scalaz的 OptionW.cata
或者 fold
. 。正如杰森(Jason)评论的那样,命名参数使它看起来不错:
opt.fold { ifSome = _ + 1, ifNone = 0 }
现在,如果您想要的价值 None
情况是 mzero
对于一些 Monoid[M]
而且您有一个功能 f: A => M
为了 Some
情况,您可以做到这一点:
opt foldMap f
所以,
opt map (_ + 1) getOrElse 0
变成
opt foldMap (_ + 1)
我自己觉得 Option
应该有一个 apply
方法将是语态性。这样,您就可以做到这一点:
opt { _ + 1, 0 }
或者
opt { some = _ + 1, none = 0 }
实际上,对于所有代数数据结构来说,这都是很好的。