Why doesn't Option have a fold method?
I wonder wh开发者_StackOverflow社区y scala.Option
doesn't have a method fold
like this defined:
fold(ifSome: A => B , ifNone: => B)
equivalent to
map(ifSome).getOrElse(ifNone)
Is there no better than using map
+ getOrElse
?
I personally find methods like cata
that take two closures as arguments are often overdoing it. Do you really gain in readability over map
+ getOrElse
? Think of a newcomer to your code: What will they make of
opt cata { x => x + 1, 0 }
Do you really think this is clearer than
opt map { x => x + 1 } getOrElse 0
In fact I would argue that neither is preferable over the good old
opt match {
case Some(x) => x + 1
case None => 0
}
As always, there's a limit where additional abstraction does not give you benefits and turns counter-productive.
It was finally added in Scala 2.10, with the signature fold[B](ifEmpty: => B)(f: A => B): B
.
Unfortunately, this has a common negative consequence: B
is inferred for calls based only on the ifEmpty
argument, which is in practice often more narrow. E.g. (a correct version is already in the standard library, this is just for demonstration)
def toList[A](x: Option[A]) = x.fold(Nil)(_ :: Nil)
Scala will infer B
to be Nil.type
instead of desired List[A]
and complain about f
not returning Nil.type
. Instead, you need one of
x.fold[List[A]](Nil)(_ :: Nil)
x.fold(Nil: List[A])(_ :: Nil)
This makes fold
not quite equivalent to corresponding match
.
You can do:
opt foldLeft (els) ((x, y) => fun(x))
or
(els /: opt) ((x,y) => fun(x))
(Both solutions will evaluate els
by value, which might not be what you want. Thanks to Rex Kerr for pointing at it.)
Edit:
But what you really want is Scalaz’s catamorphism cata
(basically a fold
which not only handles the Some
value but also maps the None
part, which is what you described)
opt.cata(fun, els)
defined as (where value
is the pimped option value)
def cata[X](some: A => X, none: => X): X = value match {
case None => none
case Some(a) => some(a)
}
which is equivalent to opt.map(some).getOrElse(none)
.
Although I should remark that you should only use cata when it is the ‘more natural’ way of expressing it. There are many cases where a simple map
–getOrElse
suffices, especially when it involves potentially chaining lots of map
s. (Though you could also chain the fun
s with function composition, of course – it depends on whether you want to focus on the function composition or the value transformation.)
As mentioned by Debilski, you can use Scalaz's OptionW.cata
or fold
. As Jason commented, named parameters make this look nice:
opt.fold { ifSome = _ + 1, ifNone = 0 }
Now, if the value you want in the None
case is mzero
for some Monoid[M]
and you have a function f: A => M
for the Some
case, you can do this:
opt foldMap f
So,
opt map (_ + 1) getOrElse 0
becomes
opt foldMap (_ + 1)
Personally, I think Option
should have an apply
method which would be the catamorphism. That way you could just do this:
opt { _ + 1, 0 }
or
opt { some = _ + 1, none = 0 }
In fact, this would be nice to have for all algebraic data structures.
精彩评论