scala-library-next icon indicating copy to clipboard operation
scala-library-next copied to clipboard

Add more partial function operations

Open martijnhoekstra opened this issue 5 years ago • 3 comments

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?

martijnhoekstra avatar Oct 30 '20 09:10 martijnhoekstra

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?

NthPortal avatar Dec 03 '20 05:12 NthPortal

👍 on the flatCollect

Lasering avatar Jul 06 '22 00:07 Lasering

mapPartial and flatMapPartial are indeed very handy. I often need something like it. I call them transform and flatTransform thought

jozic avatar Jul 06 '22 14:07 jozic