为什么没有选项有折叠方法?
我想知道为什么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))
(这两个解决scheme都会 根据价值 评估 els
,这可能不是你想要的。感谢Rex Kerr指出了这一点。)
编辑:
但是,你真正想要的是斯卡拉斯的变形 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)
。
虽然我应该说,只有在“更自然”的expression方式时才应该使用cata。 有很多情况下,一个简单的map
– getOrElse
就足够了,尤其是当它涉及到可能链接大量的map
。 (当然,你也可以把function组合连锁在一起,这取决于你是想把重点放在function组合还是价值转换上。)
我个人觉得像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
。
正如Debilski所提到的,你可以使用Scalaz的OptionW.cata
或者fold
。 正如贾森评论说,命名参数使这看起来不错:
opt.fold { ifSome = _ + 1, ifNone = 0 }
现在,如果对于某些Monoid[M]
,在None
情况下你想要的值是mzero
对于某些情况你有一个函数f: A => M
,你可以这样做:
opt foldMap f
所以,
opt map (_ + 1) getOrElse 0
变
opt foldMap (_ + 1)
就个人而言,我认为Option
应该有一个apply
方法,这将是变形。 这样你就可以做到这一点:
opt { _ + 1, 0 }
要么
opt { some = _ + 1, none = 0 }
事实上,对于所有的代数数据结构来说,这将是很好的。