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

Add Semigroupal for Monoidal hierarchy, fixes #740 #795

Merged
merged 8 commits into from
Jan 27, 2016

Conversation

adelbertc
Copy link
Contributor

  • Make (new) Semigroupal extend Functor
  • Add Monoidal and associated tests
  • Applicative extends Monoidal

So while I was doing this it has become even more apparent that we run into some strange-ness having both Apply/Applicative and Semigroupal/Monoidal. Currently we have Apply extends Monoidal (now Semigroupal) so we sort of give special treatment to Apply which doesn't particular make sense to me. Should we delete one or the other?

/cc @julienrf who did the initial work on Monoidal and @mpilquist who is our resident expert :-)

@adelbertc adelbertc changed the title Add Semigroupal for Monoidal hierarchy Add Semigroupal for Monoidal hierarchy, fixes #740 Jan 10, 2016
@codecov-io
Copy link

Current coverage is 89.27%

Merging #795 into master will increase coverage by +0.12% as of 33a9c57

@@            master    #795   diff @@
======================================
  Files          168     168       
  Stmts         2315    2321     +6
  Branches        75      75       
  Methods          0       0       
======================================
+ Hit           2064    2072     +8
  Partial          0       0       
+ Missed         251     249     -2

Review entire Coverage Diff as of 33a9c57

Powered by Codecov. Updated on successful CI builds.

* or more) within a context, which can then be mapped over via the [[Functor]]
* instance.
*/
@typeclass trait Semigroupal[F[_]] extends Functor[F] {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think that’s not a good idea to restrict Semigroupal to be a specialization of Functor. For instance, you can not anymore implement Semigroupal[Show].

Copy link
Member

Choose a reason for hiding this comment

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

Agreed, this would also prevent a Semigroupal[Codec].

@mpilquist
Copy link
Member

I'm not really comfortable with the term Semigroupal, though I don't know the category theory well enough to know if removing the unit (here, pure) from a lax monoidal functor would yield a lax "semigroupal" functor. This is too loose of reasoning for me. I'd prefer names that were more descriptive of the operation.

I also don't think we should have type classes that are equivalent -- e.g., I don't think there's a need for both applicative and monoidal as they are represented in this PR.

My preference is that we leave the canonical type class hierarchy:

invariant ← functor ← apply ← applicative

We then create a new type class:

@typeclass trait Product[F[_]] {
  def product[A, B](fa: F[A], fb: F[B]): F[(A, B)]
}

We then change Apply to extend Product.

We then change the Apply and Applicative laws to be implemented in terms of product, map, and pure, along with adding an ap consistency test.

When creating an instance of Apply or Applicative, the implementor should have a choice of defining the instance in terms of map, product, and pure, or in terms of ap and pure. Allowing implementors this freedom is likely out of scope for this issue though, because it is better addressed when derived implementations are separated from the type class interfaces.

@Fristi
Copy link
Contributor

Fristi commented Jan 11, 2016

Product clashes with the trait scala.Product

Make (new) Semigroupal extend Functor

I would rather see Semigroupal a typeclass which does not extend anything. Monoidal should extend it and when you equip it with Functor it becomes Apply and when you equip it with Invariant or Contravariant it becomes 'something' else, not sure about the naming here. Any reference to Haskell/category theory maybe? Also if you look at Invariant and Contravariant they are not equip with any pure method. Are there other type classes which do that ?

@adelbertc
Copy link
Contributor Author

@mpilquist Ah that sounds good, new PR coming in shortly..

in terms of Product do we want to conflict with scala.Product? Perhaps we can call it Zip ? Cartesian ?

@mpilquist
Copy link
Member

Cartesian works for me.

@adelbertc adelbertc force-pushed the monoidal-redux branch 3 times, most recently from 65cf576 to d85cf4f Compare January 13, 2016 01:03
@ceedubs
Copy link
Contributor

ceedubs commented Jan 15, 2016

Sorry @adelbertc this has some merge conflicts.

@adelbertc
Copy link
Contributor Author

@mpilquist @julienrf review pls :D

new MonoidalBuilder[F] |@| self |@| fb
abstract class CartesianOps[F[_], A] extends Cartesian.Ops[F, A] {
def |@|[B](fb: F[B]): CartesianBuilder[F]#CartesianBuilder2[A, B] =
new CartesianBuilder[F] |@| self |@| fb

def *>[B](fb: F[B])(implicit F: Functor[F]): F[B] = F.map(typeClassInstance.product(self, fb)) { case (a, b) => b }

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe you should also rename the file to cartesian.scala

@julienrf
Copy link
Contributor

Hi, thanks for working on this topic!

I appreciate the value of this PR, renaming Monoidal into Cartesian and adding two laws for Applicative. I think we could push the work a bit further and do the following:

  • introduce a Monoidal typeclass
trait Monoidal[F[_]] extends Cartesian[F] {
  def pure[A](a: A): F[A]
}
  • Define identity laws only in terms of Monoidal:
def monoidalLeftIdentity[A](fa: F[A]): ((F[Unit], F[A]), F[A]) =
    (F.product(F.pure(()), fa)), fa)
def monoidalRightIdentity
  • Provide ways to actually check them for Functor, Contravariant and Invariant, by implementing isomorphisms between (F[Unit], F[A]) and F[A] (and (F[A], F[Unit]) and F[A]), as it was done for the associativity law.
  • Implementing Monoidal for as many data types as possible (e.g. Applicative but also Show, Const, etc.)

If needed, we could capture pure in its own typeclass:

trait Pure[F[_]] {
  def pure[A](a: A): F[A]
}

And then define Monoidal in terms of Pure:

trait Monoidal[F[_]] extends Cartesian[F] with Pure[F]

I don’t remember if this is needed or not.

@julienrf julienrf mentioned this pull request Jan 19, 2016
@julienrf
Copy link
Contributor

I’m OK for this work to be merged as it is, and to continue on working on it as per #817

@adelbertc
Copy link
Contributor Author

@mpilquist @ceedubs review? :D

trait Isomorphisms[F[_]] {
def associativity[A, B, C](fs: (F[(A, (B, C))], F[((A, B), C)]))(implicit EqFABC: Eq[F[(A, B, C)]]): Prop
def leftIdentity[A](fs: (F[(Unit, A)], F[A]))(implicit EqFA: Eq[F[A]]): Prop
def rightIdentity[A](fs: (F[(A, Unit)], F[A]))(implicit EqFA: Eq[F[A]]): Prop
Copy link
Contributor

Choose a reason for hiding this comment

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

This is not very important, but I’m currently reading this paper and it seems that the above isomorphisms should be named associator, leftUnitor and rightUnitor, to be consistent with the literature.

@ceedubs
Copy link
Contributor

ceedubs commented Jan 26, 2016

@adelbertc sorry, I don't think I'm qualified to review this one. I'm hoping @mpilquist will weigh in. When you, @julienrf, and @mpilquist are all happy with it, then I think it's good to merge.

@mpilquist
Copy link
Member

👍

@mpilquist
Copy link
Member

@adelbertc Let's merge after the conflicts are fixed.

@adelbertc
Copy link
Contributor Author

Merge conflicts resolved, will merge when Travis gives the green light.

adelbertc added a commit that referenced this pull request Jan 27, 2016
Add Semigroupal for Monoidal hierarchy, fixes #740
@adelbertc adelbertc merged commit 9780e8f into typelevel:master Jan 27, 2016
@stew stew removed the in progress label Jan 27, 2016
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.

8 participants