-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Remove FunctorFilter #1365
Comments
@kcsongor thank you for raising your concerns. I'm not sure that I followed all of your comments, but I'll respond to a couple things that caught my attention. emptyI've seen both you and @non mention that In this comment @non said:
While I think that every FunctorFilter instances as opposed to other type classes@kcsongor correct me if I'm wrong, but my understanding is that in your comment above you are saying that Firstly, I think that in many cases you can get better performance out of
|
We can implement scala> :paste
// Entering paste mode (ctrl-D to finish)
def filter[F[_]: Alternative, A](fa: F[A])(cond: A => Boolean): F[A] =
{
var acc = Alternative[F].empty[A]
Alternative[F].map(fa) { x =>
if (cond(x)) acc = Alternative[F].combineK(acc, Alternative[F].pure(x))
else ()
}
acc
} Is |
@eed3si9n I think you can't define |
Here's a summary of my findings in this area, working on cats-mtl.
The moment you start to say something about the As it is, if there are any further thoughts on this issue an issue should be opened at cats-mtl. |
I argue that the
FunctorFilter
type class is unnecessary:First of all, all instances need to have a well-defined
empty
(even though this is not encoded in the type-class itself, but if I send all values toNone
, then the resulting 'thing' must not contain anyB
s, because I could only get aB
from theA => Option[B]
function).Then there is the other thing, that all the
None
results disappear from the resulting Functor.Let's try to define it for a very simple example,
Option
.I start with
Some(5)
, and I filter it with(_ => None)
. The outcome isNone
. Notice how theSome
constructor changed to theNone
constructor. This is something that an ordinaryFunctor
can't do!This means that whatever
FunctorFilter
actually is, it needs to know how to produce new values based on the content of an existing value.This is also evidenced by the fact that it allows you to reduce the number of elements in the container. How can we do that? For example, you can use something like
Foldable
'sfoldMap
, to map all elements to someMonoid
, then combine those. Since here, the resulting structure isF[B]
, it means that if we go theFoldable
route to achieve filtering, we need a monoid instance forF[B]
. (note that we already needed theempty
). Actually, I need aMonoid[F[B]]
for allB
.Using
Foldable
this way really just means that we filter the structure by rebuilding it, leaving out the elements we don't need.Furthermore, under the premise that we have a
Foldable
that canfilter
things, I can specialise thefoldMap
function fromdef foldMap[A, B](fa: F[A])(f: A => B)(implicit B: Monoid[B]): B
toflatMap[A, B](fa: F[A])(afb: A => F[B]) => F[B]
, since we required aMonoid[F[B]]
for allB
. This would mean that allFunctorFilter
s admit aFlatMap
instance too. But given the above instances,FunctorFilter
doesn't add any extra value.This would mean that a
Foldable
, aMonoid
, and aFlatMap
instance are a necessary and sufficient condition. Also note, however, that we never required the existence of apure
function, so aMonad
constraint is not needed.I couldn't come up with any other approach that doesn't eventually reduce to a
Foldable
one way or another. If someone could provide examples where this isn't the case, I would be very interested.The text was updated successfully, but these errors were encountered: