Skip to content

Having ap depend on map can introduce loops #232

Closed
@hdgarrood

Description

@hdgarrood

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.

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