scala-library-next
scala-library-next copied to clipboard
Add more partial function operations
I miss having a form of filter that takes a partial function. It feels really natural to me to be able to write
List(1, 2, 3, 4, 5, 6).filter {
case i if i > 3 => i % 2 == 0
}
resulting in List(4, 6)
Of course, you could use collect for that case and move the rhs of the pattern to the guard, but quite often, the expression is more complex, and you really want to use a block.
A definition for that could be def filter(pf: PartialFunction[A, Boolean]) = filter(pf.applyOrElse(_, _ => false) (though adding this by extension probably isn't possible since an applicable method already exists in "classic" filter).
I find the same thing lacking for something between collect and flatMap: I'd love a def flatCollect[B](pf: PartialFunction[A, B]) = flatMap(pf.applyOrElse(_, _ => empty)). In action:
List(1, 2, 3, 4, 5, 6).flatCollect {
case i if i > 3 => List(i, i)
}
// List(4, 4, 6, 6)
other potential partial variations of functions that I can kinda see but don't have strong feelings about:
def mapPartial[A1 >: A](pf: PartialFunction[A, A1]) = map(pf.applyOrElse(_, identity))
def flatMapPartial[A1 >: A](pf: PartialFunction[A, CC[A1]]) = flatMap(pf.applyOrElse(_, x => x +: empty)
WDYT?
I'm not sure your first example is great, as it could be simplified to List(1, 2, 3, 4, 5, 6).filter { (i > 3) && (i % 2 == 0) }.
I am of two minds about this. On the one hand, these can be very useful and simplify code (especially the filter one); on the other hand, the standard library cannot have dedicated, bespoke methods for everything you could ever want to do; rather, it has methods that make it easy to accomplish most things you want to do with little extra effort (I can't recall who said this that I'm stealing it from).
One great example of the latter thought is the groupBy family of methods. There are many related grouping operations that are a little tedious to do with just those 3 methods, but at the same time, we can't have 100 group<Op> methods. For example, I commonly do groupMapReduce(identity)(_ => 1)(_ +_) to count how many times an element occurs in a Seq. Should it have a dedicated groupCount or elemCount method? idk. where does it end? what about groupReduce without the Map bit? groupFlatMap(Reduce)? groupCollect?
👍 on the flatCollect
mapPartial and flatMapPartial are indeed very handy. I often need something like it. I call them transform and flatTransform thought