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

Justify Bimonad #30

Closed
tpolecat opened this issue Feb 1, 2015 · 24 comments
Closed

Justify Bimonad #30

tpolecat opened this issue Feb 1, 2015 · 24 comments

Comments

@tpolecat
Copy link
Member

tpolecat commented Feb 1, 2015

Per a conversation with Kmett that I only understood about 10% of (i.e., better than usual) the notion of Bimonad is interesting only if the Monad and Comonad instances are each others' co-algebras, otherwise we can't say anything interesting. It's also not clear whether these things we can say lead to useful derived operations. So I suggest removing Bimonad unless we can state its law and identify operations that it provides; closing the diamond is fun but not reason enough.

@non
Copy link
Contributor

non commented Feb 1, 2015

I agree that unless we can find additional laws and/or derived operations then Bimonad[_] doesn't seem as useful.

I'm hoping to get law-checking implemented today, so I'll look at adding this requirement.

@stew
Copy link
Contributor

stew commented Jun 5, 2015

I say kill the Bimonad

@ghost
Copy link

ghost commented Jun 27, 2015

Please le me know before you kill it as it's the only thing I've used in porting banana-rdf to Cats!! Typical old use case:

import scalaz._
import scalaz.syntax._, monad._, comonad._

abstract class SerialisationTestSuite[Rdf <: RDF, M[+_] : Monad : Comonad, Sin, Sout]( ......

  // both Monad and Comonad are Functors, so they compete for the
  // syntax. So we choose arbitrarily one of them.
  // TODO @betehess to ask scalaz people
  val M = Monad[M]
  import M.functorSyntax._

  .....

 val graph = reader.read(new StringReader(soutString), rdfCore).copoint

And new version:

import cats.Bimonad
import cats.implicits._

abstract class SerialisationTestSuite[Rdf <: RDF, M[+_] : Bimonad, Sin, Sout](   ....

val graph = reader.read(new StringReader(soutString), rdfCore).extract

Perhaps independent of your decision, the general look'n'feel of the new is much nicer, including copoint -> extract

For the full picture, the default M we have is a TryInstance. Old:

import scalaz.{ Monad, Comonad }
import scala.util.Try

object tryInstances {
  implicit final val TryInstance = new Monad[Try] with Comonad[Try] {
    def point[A](a: => A): Try[A] = Try(a)
    def bind[A, B](fa: Try[A])(f: A => Try[B]): Try[B] = fa flatMap f
    override def map[A, B](fa: Try[A])(f: A => B): Try[B] = fa map f
    def cobind[A, B](fa: Try[A])(f: Try[A] => B): Try[B] = Try(f(fa))
    override def cojoin[A](a: Try[A]): Try[Try[A]] = Try(a)
    def copoint[A](p: Try[A]): A = p.get
  }
}

New:

import cats.Bimonad
import scala.util.Try

object tryInstances {
  implicit final val TryInstance = new Bimonad[Try] {

    def pure[A](a:  A): Try[A] = Try(a)

    def flatMap[A, B](fa: Try[A])(f: A => Try[B]): Try[B] = fa flatMap f

    override def map[A, B](fa: Try[A])(f: A => B): Try[B] = fa map f

    def coflatMap[A, B](fa: Try[A])(f: Try[A] => B): Try[B] = Try(f(fa))

    def extract[A](p: Try[A]): A = p.get
  }
}

@ghost
Copy link

ghost commented Aug 25, 2015

Please le me know before you kill it as it's the only thing I've used in porting banana-rdf to Cats!!

FYI... I've changed banana-rdf to use Monad, Comonad, alleycats.tryInstances, so there is now no dependency on Bimonad

@milessabin
Copy link
Member

I'd push back by saying that something can be interesting and useful without being mathematically interesting (or useful).

@ghost
Copy link

ghost commented Aug 25, 2015

Well, in terms of being useful, Bimonad is much more user friendly

Bimod version:

import cats.Bimonad
import cats.implicits._

abstract class SerialisationTestSuite[Rdf <: RDF, M[+_] : Bimonad, Sin, Sout](   ....

val graph = reader.read(new StringReader(soutString), rdfCore).extract

new :

import cats.{Applicative, Comonad, Monad}
import cats.implicits._

abstract class SerialisationTestSuite[Rdf <: RDF, M[+_] : Monad : Comonad, Sin, Sout]( ......

        // both Monad and Comonad are Functors, so they compete for the syntax......
  // Luckily I had this comment, so I found it quite easy to work out what to do
  import Applicative.ops._

....

 val graph = reader.read(new StringReader(soutString), rdfCore).copoint

Plus the import Applicative.ops._ is repeated in a few other classes

@fthomas
Copy link
Member

fthomas commented Aug 25, 2015

Let me play devil's advocate. If we have Bimonad we should also have BiflatMap. What would be the reason to leave Bimonad in but let BiflatMap out?

@milessabin
Copy link
Member

The reason for wanting Bimonad is concision in real code. It doesn't follow from Bimonad providing that that BiflatMap would do too ... that's an empirical question. If it turned out that it does, then I don't see any reason not to add it as well.

@stew
Copy link
Contributor

stew commented Sep 2, 2015

I've changed my mind, I . I'm voting for it to stay in. now :)

@fthomas
Copy link
Member

fthomas commented Sep 2, 2015

Should we formulate laws for Bimonad? Something like pure andThen extract = identity seems useful. There may be other identities which include flatMap and coflatMap.

@non
Copy link
Contributor

non commented Sep 2, 2015

@fthomas it turns out I had a branch with exactly this law sitting around. I'll push a PR now.

@fthomas
Copy link
Member

fthomas commented Sep 2, 2015

@non, great, thanks!

Another "problem" I've with Bimonad is that its Bi has nothing to do with the Bi of Bifunctor (which we also have). The first is the combination of a structure with its dual and the other is a combination of two of the same structure.

@milessabin
Copy link
Member

Agreed that the clash of meaning on Bi is unfortunate. Something riffing on symmetry or invariance maybe?

@non
Copy link
Contributor

non commented Sep 2, 2015

https://github.com/non/cats/pull/511

I am fine with changing the name -- it seems like a good idea.

@non non mentioned this issue Sep 2, 2015
@fthomas
Copy link
Member

fthomas commented Sep 27, 2015

Since a comonad is the categorical dual of a monad, self-dual seems to be an appropriate term. SelfDualMonad?

Btw: Now that we have laws for Bimonad, I think it should stay in.

@non
Copy link
Contributor

non commented Sep 27, 2015

@fthomas would you be OK with shortening it to DualMonad? There's a nice sort of pun between the two-related-structures and the dual-of-itself concepts.

@xuwei-k
Copy link
Contributor

xuwei-k commented Sep 27, 2015

BTW ComonadApply has laws.

https://hackage.haskell.org/package/comonad-4.2.7.2/docs/Control-Comonad.html#t:ComonadApply
https://hackage.haskell.org/package/functor-apply-0.9.1/docs/Control-Comonad-Apply.html

(.) <$> u <@> v <@> w = u <@> (v <@> w)
extract (p <@> q) = extract p (extract q)
duplicate (p <@> q) = (<@>) <$> duplicate p <@> duplicate q

I think ComonadApply is isomorphic to Comoand + Apply, and ComonadApply is super class of Bimonad if Bimonad should be exists.

@fthomas
Copy link
Member

fthomas commented Sep 27, 2015

@non That pun is subtle. :-) If you google for "dual monad" you get things like "the dual of a monad is a comonad". Not sure if it would confuse people if we have DualMonad and Comonad.

Thanks @xuwei-k for the pointer. If you are right, we should be able to add those laws to BimonadLaws.

@non
Copy link
Contributor

non commented Sep 27, 2015

@xuwei-k @fthomas Do you think we should create expicit type classes that combines Coflatmap or Comonad along with Apply? We should definitely add these laws -- but would it be worth adding these structures too?

@ghost
Copy link

ghost commented Sep 28, 2015

Disclaimer: I've never, ever had a naming suggestion taken up.

DualedMonad - ie an XZY that has been Dualed with itself:

From Google:

Showing results for Dual edMond
No results found for DualedMonad 

@non
Copy link
Contributor

non commented Sep 28, 2015

I am fine with DualedMonad. I can also live with SelfDualMonad if everyone else prefers that (especially since it is an established terminology).

@fthomas
Copy link
Member

fthomas commented Nov 3, 2015

With #595 and #596 I think there is now enough justification for the Bimonad type class and name. I'd be ok with closing this issue.

@ceedubs
Copy link
Contributor

ceedubs commented Nov 3, 2015

@fthomas that sounds reasonable. What do you think, @tpolecat?

@tpolecat
Copy link
Member Author

tpolecat commented Nov 3, 2015

👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants