If we could do it all over again, could pure be a method of the Functor typeclass?

I wonder if pure couldn’t have been a method of Functor. It seems trivial enough that Functor could sport it. Of course I understand that it’s not quite doable in Haskell today, but for a new language, are there issues that I’m unaware of?

One downside that I can think of is that Functor would not be derivable anymore; if the data type has two constructors, which one would be used for pure?

2 Likes

How would such a change influence the design of Apply?

1 Like

Do you have examples of use cases for types that do not support <*>, but do support fmap and pure? I have never really felt the need for it.

2 Likes

No I don’t, it just felt “weird” to me that Functor would make you use the constructor that Applicative already uses in order to implement pure.

Interesting, thanks a lot, I did not have DeriveFunctor in mind!

I appears misguided to move functions from one type class to the other, I think the intended kmettverse hierarchy (which splits up as much as possible) is nicer than this approach. However, even they put pure into Applicative.

Also, what do you do with all the Functors that cannot be Applicative (or Pointed for that matter) and if you think that’s absurd, then here’s an example: Control.Concurrent.Async

1 Like

I’m sorry, but I don’t know what you mean. In what way does Functor make you use a constructor? Which constructor?

Rather it’s the absence of Applicative that makes one use the constructor. To create a Maybe a from an a, you need Just, which is the constructor.

But when you have Applicative, you have:

instance Applicative Maybe where
    pure = Just

Then you can use pure and not necessarily the constructor.

I don’t follow. Many Functors don’t have a sensible pure. For an extreme example: newtype VoidF a = MkVoidF Void.

6 Likes

or a Map k

semigroupoids in general illustrates why pure is “further down the FAM stack” than fmap and <*>

9 Likes

Map has Functor instance, but doesn’t have pure unless we agree that k should be Monoid in this case (I don’t agree, that doesn’t make sense in the most contexts and will restrict usage of fmap). I would prefer pure to have its own type class in a better world.

7 Likes

If we could do it all over again […]

Not quite relevant to what I’m asking, but thanks

Thanks, that’s helpful to know. :slight_smile:

Functor is a well-established name. You are suggesting a new abstraction, a Functor augmented with pure. This is a different abstraction and needs a new name, e.g. FunctorWithPure.

Now I suppose your question is this: if in our language we only had FunctorWithPure, would we miss our original Functor?

And the answer is yes, we would. Functor is a useful abstraction. Consider van Laarhoven lenses, which are defined as follows

type Lens s t a b = forall f. Functor f => (a -> f b) -> s -> f t

This is an encoding of a getter/setter pair, and it is crucial that we use Functor here because we recover the getter by instantiating f to Const a.

If we used FunctorWithPure to define a lens, then we couldn’t recover the getter because it’s impossible to define pure :: x -> Const a x for an unconstrained a. That would require us to conjure up an a out of thin air.

8 Likes

Interesting, thank you!

pure also doesn’t really have any useful laws with just fmap. Another reason it should be below Apply in the hierarchy…and then "a class for pure just becomes Applicative (analogous to Monoid and mempty).

1 Like

What about pure (f x) = fmap f (pure x)? Not useful enough?

Isn’t that a free theorem anyway?