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 monad.md #332

Merged
merged 6 commits into from
Jun 25, 2015
Merged

add monad.md #332

merged 6 commits into from
Jun 25, 2015

Conversation

woparry
Copy link

@woparry woparry commented Jun 2, 2015

implicit def traverseMonadCompose[F[_], G[_]](implicit
FM: Monad[F],
GM: Monad[G],
GT: Traverse[G]
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 @larsrh tried to prove the monad laws given these constraints and arrived at the conclusion that Traverse is not expressive enough? The types certainly line up though..

Copy link
Author

Choose a reason for hiding this comment

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

I was basing this assertion on 12.7.6 of Functional Programming in Scala by Chiusano and Bjarnason, which has this as an exercise.

However, it doesn't address the derivation of the laws, and after searching today I can't find any references to this construction in the literature.

Composing monads (Jones/Duponcheel 1993, http://web.cecs.pdx.edu/~mpj/pubs/RR-1004.pdf) has some information in this direction, though it's not trivial to work out whether the sequence laws laid out in The Essence of the Iterator Pattern (Gibbons/Oliveira 2010, https://www.cs.ox.ac.uk/jeremy.gibbons/publications/iterator.pdf) are sufficient to derive the laws they require on swap.

Should I just drop this section?

@woparry
Copy link
Author

woparry commented Jun 3, 2015

For context, here's the scalaz mailing list thread on the subject:
https://groups.google.com/d/msg/scalaz/w2k9ycdjx84/dyx5vDOQyZkJ

@runarorama
Copy link

Cross-posted from Scala-Functional:

For a distributive law from one monad to another, you need the lemmas:

sequenceA . fmap return = return

and

sequenceA . fmap join = join . fmap sequenceA . sequenceA

These both follow from the laws for traversables. [EDIT: does not actually work for non-commutative monads]

Pentagon identity:
sequenceA . fmap join
-- naturality of traverse
join . uncompose . sequenceA . fmap Compose
-- compositionality of traverse
join . uncompose . Compose . fmap sequenceA . sequenceA
-- simplify
join . fmap sequenceA . sequenceA
-- QED

Triangle identity:
sequenceA . fmap return
-- rewrite to natural applicative transformations
sequenceA . fmap (return . out) . (fmap Identity)
-- naturality of traverse
return . out . sequenceA . (fmap Identity)
-- identity law for traverse
return . out . Identity
-- simplify
return
-- QED

See here for further reading on distributive laws between monads:

http://ncatlab.org/nlab/show/distributive+law

@adelbertc
Copy link
Contributor

Well then.. looks like we're good :-)

Awesome as usual @runarorama , thanks!

@larsrh
Copy link
Contributor

larsrh commented Jun 4, 2015

That's weird, last time I ran ScalaCheck on these constructions gave counterexamples. I'll try to reproduce the problem.

@runarorama
Copy link

The first step of the pentagon is unjustified for e.g. List. Counterexamples:

x = Compose [[-1,2]]
y = Compose [[],[4,2],[-4,-3,-4,-1],[-3,-4]]
t = join . uncompose

Now t ((,) <$> x <*> y) = (,) <$> t x <*> t y does not hold as required by the naturality law for Traverse. So yeah, you need a properly constructed distributive law and you cannot consistently get it from Traverse[T[_]] for all T.

It only works for commutative monads. That is join is only an Applicative homomorphism if its monad is commutative, for the same reason that mappend is not a monoid homomorphism unless its monoid is commutative.

@xuwei-k
Copy link
Contributor

xuwei-k commented Jun 5, 2015

scalaz/scalaz#921

@stew
Copy link
Contributor

stew commented Jun 5, 2015

@woparry first of all, Thanks!

@stew
Copy link
Contributor

stew commented Jun 5, 2015

do we care that the flatten method is actually introduced in the FlatMap type instead of Monad? do we want to make that clear to the reader, or leave that as an implementation detail?

@stew
Copy link
Contributor

stew commented Jun 5, 2015

@woparry can we amend the part in question about an inner traverse that just mentions a caveat with some external links to the relevant discussions?

@runarorama
Copy link

Could just say that a distributive law is required, with links to what that means

@woparry
Copy link
Author

woparry commented Jun 5, 2015

I don't think it's worth having those technical details in introductory docs.

I've replaced the traverse example in the composition section with a monad transformer example (for Option).

@non
Copy link
Contributor

non commented Jun 5, 2015

Looks good to me. Thanks! 👍

@woparry
Copy link
Author

woparry commented Jun 15, 2015

Request for feedback - is there anything confusing/misleading here that should be corrected before merging?

}
```

This sort of construction is called a monad transformer.
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure I would say this is how we've been approaching monad transformers. In #304, OptionT is its own class that wraps F[Option[A]]. We don't define a Monad[F[Option[?]] directly. I think doing so would lead to ambiguity as to whether you were trying to map over F or the inner option, wouldn't it?

The difference may be subtle, but I'm a bit hesitant to say something in the docs that is different than the actual Cats implementation (though I should note that the referenced pull request is not yet merged).

@codecov-io
Copy link

Current coverage is 60.06%

Merging #332 into master will change coverage by +4.22% by 715d9cb

Coverage Diff

@@            master    #332   diff @@
======================================
  Files          136     132     -4
  Stmts         1816    1600   -216
  Branches        25      25       
  Methods          0       0       
======================================
- Hit           1014     961    -53
  Partial          0       0       
+ Missed         802     639   -163

Powered by Codecov

@ceedubs
Copy link
Contributor

ceedubs commented Jun 25, 2015

👍

ceedubs added a commit that referenced this pull request Jun 25, 2015
@ceedubs ceedubs merged commit 18e24f4 into typelevel:master Jun 25, 2015
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.

10 participants