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
?
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.
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
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 Functor
s don’t have a sensible pure
. For an extreme example: newtype VoidF a = MkVoidF Void
.
or a Map k
semigroupoids
in general illustrates why pure
is “further down the FAM stack” than fmap
and <*>
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.
If we could do it all over again […]
Not quite relevant to what I’m asking, but thanks
Thanks, that’s helpful to know.
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.
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
).
What about pure (f x) = fmap f (pure x)
? Not useful enough?
Isn’t that a free theorem anyway?