Generalize functors to restricted functors
See original GitHub issueFunctor is currently described as:
map :: Functor f => f a ~> (a -> b) -> f b
The fact that there’s no constraints on a
or b
means this is a functor over the category of all types in JS: it maps a morphism between any two types a -> b
to a morphism f a -> f b
(and implicitly, any type a
to the type f a
).
In some cases, a type may exhibit the characteristics of being a legal functor over some universe of types, but not behave as a legal functor over every conceivable type.
For example, Promise#then
can be used to form a legal functor over non-“thenable” types, and those types only. Consider the following implementation:
const map = f => x => x.then(f)
map(x => x * 2)(Promise.resolve(10)) // Behaves as legal functor, produces Promise containing 20
map(x => ({ then: () => x * 2 }))(Promise.resolve(10)) // Does not behave as legal functor
While Promise
does not form a legal functor over morphisms between all types, as shown above, it certainly does form a functor over types that satisfy a constraint (in this case, x => !isThenable(x)
).
If the Fantasy Land spec allowed formalization of “functor over the category of some types”, many more types naturally occurring in JS could be instantiated as lawful functors/applicatives/monads and benefit from code that works with these abstract classes.
RFunctor
could hypothetically look something like this:
class RFunctor (s :: * -> Constraint) f where
rmap :: (s a, s b) => f a ~> (a -> b) -> f b
instance RFunctor NonThenable Promise where ...
The existing Functor
class would simply be RFunctor
for a choice of constraint that accepts all types.
The specification has a choice between simply making the behavior of rmap
with respect to non-suitable morphisms undefined, or requiring implementers to provide a suitable :: a -> Boolean
implementation which will be used to produce type errors for invalid morphisms.
Prior art:
Not sure if @hsenag is active on here, but maybe he has some thoughts.
Issue Analytics
- State:
- Created 5 years ago
- Comments:6
Top GitHub Comments
/shrug I’ve said my bit: I worry about misinterpretation. Ultimately, though, this is up to the collaborators within this repository, so I’m the wrong person to be talking to 😅
I’m afraid I’m gonna have to give this a 👎 simply because it contains the word “functor”. We don’t have constraints (let alone constraint kinds) in JS, and I think this opens us up to a lot of misinterpretation. For example,
Promise
isn’t a functor, and it’s something I have to explain fairly regularly - I think saying “it’s an rfunctor” implies that rfunctor is somehow related to functor, which (in JS) it isn’t.I see where you’re coming from, but I’m already worried when we start talking about promises or sets as “lawful functors/applicatives/monads”, because they’re simply not - as soon as you introduce constraints, you un-introduce “functor” 😦