Skip to content

Remove FunctorFilter #1365

@kcsongor

Description

@kcsongor

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 to None, then the resulting 'thing' must not contain any Bs, because I could only get a B from the A => 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 is None. Notice how the Some constructor changed to the None constructor. This is something that an ordinary Functor 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's foldMap, to map all elements to some Monoid, then combine those. Since here, the resulting structure is F[B], it means that if we go the Foldable route to achieve filtering, we need a monoid instance for F[B]. (note that we already needed the empty). Actually, I need a Monoid[F[B]] for all B.
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 can filter things, I can specialise the foldMap function from def foldMap[A, B](fa: F[A])(f: A => B)(implicit B: Monoid[B]): B to
flatMap[A, B](fa: F[A])(afb: A => F[B]) => F[B], since we required a Monoid[F[B]] for all B. This would mean that all FunctorFilters admit a FlatMap instance too. But given the above instances, FunctorFilter doesn't add any extra value.

This would mean that a Foldable, a Monoid, and a FlatMap instance are a necessary and sufficient condition. Also note, however, that we never required the existence of a pure function, so a Monad 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions