-
Notifications
You must be signed in to change notification settings - Fork 91
Description
Before #229 was merged, ap depended on bind and pure. Now that #229 has been merged, ap depends on bind and map.
This means that defining apply = ap as well as map = liftA1 will cause loops. When you try to use map with such a type, the following happens:
map- is implemented via
liftA1, - which calls
apply, - which is implemented via
ap, - ... which calls
map, and we loop.
Effect is one such type; this was causing failures in purescript/purescript-refs#29 (comment).
I think the law changes in #229 were correct, but perhaps changing ap to have a Bind constraint rather than a Monad constraint should be reverted? I think changing the rules for when it's safe to use these default implementation functions is probably too dangerous a breaking change to be justifiable. Maybe default implementation functions should only be allowed to use type class members from classes which are below the class which they are providing a default implementation for in the hierarchy? That is, it's fine for liftA1 to depend on both apply and pure, because they are members from Apply and Applicative respectively, which are both below Functor. Also, it's fine for ap to depend on both bind and pure, because they are from Bind and Applicative, which are both below Apply. However, it's not fine for ap to depend on map, because that's from Functor, which is above Apply.