我想知道为什么scala.Option
没有fold
定义这样的方法:
fold(ifSome: A => B , ifNone: => B)
相当于
map(ifSome).getOrElse(ifNone)
没有比使用map
+更好的getOrElse
吗?
我想知道为什么scala.Option
没有fold
定义这样的方法:
fold(ifSome: A => B , ifNone: => B)
相当于
map(ifSome).getOrElse(ifNone)
没有比使用map
+更好的getOrElse
吗?
我个人发现像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
的 .
你可以做:
opt foldLeft (els) ((x, y) => fun(x))
或者
(els /: opt) ((x,y) => fun(x))
(两种解决方案都将按 els
价值进行评估,这可能不是您想要的。感谢Rex Kerr指出它。)
编辑:
但是你真正想要的是 Scalaz 的catamorphism cata
(基本上 afold
不仅处理Some
值而且映射None
部分,这就是你所描述的)
opt.cata(fun, els)
定义为(value
拉皮条的期权价值在哪里)
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
–<code>getOrElse 就足够了,尤其是当它涉及到潜在地链接大量map
s 时。(当然,您也可以将fun
s 与函数组合链接起来——这取决于您是要关注函数组合还是值转换。)
正如 Debilski 所提到的,您可以使用 ScalazOptionW.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
方法,那就是catamorphism。这样你就可以这样做:
opt { _ + 1, 0 }
或者
opt { some = _ + 1, none = 0 }
事实上,这对于所有代数数据结构来说都是很好的。