Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sketch of approach to fix #168 #370

Closed
wants to merge 6 commits into from
Closed

Sketch of approach to fix #168 #370

wants to merge 6 commits into from

Conversation

woparry
Copy link

@woparry woparry commented Jun 23, 2015

This is the first set of tests that verify your typeclass implementations are interchangeable with the defaults.

The pieces:

FunctorFromApplicative and ApplicativeFromMonad are mixins that define (map, ap) in terms of (ap, flatMap). They make it easy to build instances of Monad and Applicative by only defining the core functions (pure and (ap or flatMap)).

Applicative, FlatMap, Traverse, etc no longer provide default implementations of ap and map.
You must override them yourself with an efficient version (recommended) or mix in the appropriate trait from canon to get the defaults.

The canon package object get canonicalMonad and canonicalApplicative, which use the mixins to build an implementation using the default versions of derived functions.

The Laws use these to verify that the instance implementations of (map, ap, map2) match the canonical implementations.

trait ApplicativeFromMonad[F[_]] extends Applicative[F] with FunctorFromApplicative[F] { self: Monad[F] =>
def ap[A, B](fa: F[A])(ff: F[A => B]): F[B] =
flatMap(ff)(f => flatMap(fa)(a => pure(f(a))))
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, one question I have is -- why are we structuring these traits using self-types? My natural inclination would have been to define something like:

trait ApplicativeFromMonad[F[_]] extends Monad[F]
  with FunctorFromApplicative[F] {
  def ap[A, B](fa: F[A])(ff: F[A => B]): F[B] =
    flatMap(ff)(f => flatMap(fa)(a => pure(f(a))))
}

Is there a reason this doesn't work? The only reason I ask is that seen in isolation its purpose might not be totally apparent. In fact, defined this way, we could name them CanonicalMonad[F], CanonicalApplicative[F], and so on.

What d you think? Is there something I'm missing?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This works. If the purpose is not apparent I will go with your approach, the only reason to go with self-types here was because I thought they expressed the intent better.

I read the signature

trait FunctorFromApplicative[F[_]] extends Functor[F] { self: Applicative[F] =>

as "This trait provides a Functor[F] when mixed into an Applicative[F]".

Conversely, I don't believe the signature

trait CanonicalApplicative[F[_]] extends Applicative[F] {

provides as much information about how it is intended to be used (as a mix-in).

I expected the mix-in approach to scale better when you want to pick-and-choose which defaults you want -- for example

implicit val optionInstance =
  new Monad[Option] with Traverse[Option] with FunctorFromTraverse[Option] {
    ...
  }

and

implicit val optionInstance =
  new Monad[Option] with Traverse[Option] with FunctorFromApplicative[Option] {
    ...
  }

should have different implementations of map.

@codecov-io
Copy link

Current coverage is 60.69%

Merging #370 into master will change coverage by +4.58% by 7bd1467

Coverage Diff

@@            master    #370   diff @@
======================================
  Files          136     135     -1
  Stmts         1818    1651   -167
  Branches        25      25       
  Methods          0       0       
======================================
- Hit           1020    1002    -18
  Partial          0       0       
+ Missed         798     649   -149

Powered by Codecov

@non
Copy link
Contributor

non commented Jun 26, 2015

Hi @woparry, sorry for the radio silence. I've been busy and I'm trying to consider exactly how we should structure something like this (and how we should talk about it).

ceedubs added a commit to ceedubs/cats that referenced this pull request Dec 9, 2015
A `monadFilterConsistency` law was added in
8f7a110 but wasn't hooked up in the
tests. This might be better accomplished with something like typelevel#370, but
in the interim I think we should at least hook it up.
@ghost
Copy link

ghost commented Feb 22, 2016

Hello, did you also consider

  • monad => (kleisl)i arrow
  • arrow => applicative

I could help you with this

see http://homepages.inf.ed.ac.uk/wadler/papers/arrows-and-idioms/arrows-and-idioms.pdf

@easel
Copy link
Contributor

easel commented Sep 25, 2018

This PR looks pretty stale, can we close it out?

@kailuowang
Copy link
Contributor

Closing stale PRs. Feel free to reopen if there is interest to revive the effort.

@kailuowang kailuowang closed this Aug 5, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants