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 existsM and forallM to Foldable #1784

Merged
merged 2 commits into from
Aug 7, 2017

Conversation

aryairani
Copy link
Contributor

I was missing these utility functions. I've been out of the loop for a while so let me know if I didn't contrib right, and I'll be happy to update.

@codecov-io
Copy link

codecov-io commented Aug 4, 2017

Codecov Report

Merging #1784 into master will increase coverage by <.01%.
The diff coverage is 100%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #1784      +/-   ##
==========================================
+ Coverage   94.87%   94.88%   +<.01%     
==========================================
  Files         241      241              
  Lines        4139     4147       +8     
  Branches      103      110       +7     
==========================================
+ Hits         3927     3935       +8     
  Misses        212      212
Impacted Files Coverage Δ
core/src/main/scala/cats/Foldable.scala 100% <100%> (ø) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 0519906...9800e4a. Read the comment docs.

@kailuowang
Copy link
Contributor

kailuowang commented Aug 4, 2017

I think if you use Fordable.Source and tailRecM directly rather than foldM, you should be able to shortcircuit
e.g.

  def existsM[G[_], A](fa: F[A])(p: A => G[Boolean])(implicit G: Monad[G]): G[Boolean] = {
    val src = Foldable.Source.fromFoldable(fa)(self)
    G.tailRecM(src) { srcc => srcc.uncons match {
      case Some((a, src)) => G.map(p(a))(bb => if (bb) Right(true) else Left(src.value))
      case None => G.pure(Right(false))
    }}
  }

* res0: Option[Boolean] = Some(true)
*
* scala> F.existsM(List(1,2,3,4))(n => if (n <= 2) Option(true) else Option(false))
* res1: Option[Boolean] = Some(true)
Copy link
Contributor

Choose a reason for hiding this comment

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

might be better to have a negative test case here, e.g.

   * scala> F.existsM(List(1,2,3,4))(n => if (n > 4) Option(true) else Option(false))
   * res1: Option[Boolean] = Some(false)

@aryairani
Copy link
Contributor Author

@kailuowang Yes, but do we want it to short-circuit and skip effects? I could imagine an argument either way. For my use case, short-circuiting would probably be fine, but I didn’t want to presume that for everyone. IIRC scalaz's intentionally doesn’t shortcircuit, but I don’t know the rationale.

@kailuowang
Copy link
Contributor

kailuowang commented Aug 4, 2017

I think there is definitely a use case for short-circuiting implementation. If we have to pick from the two, I would argue we should pick the short-circuit one, because the other one isn't that cumbersome to write on use-site if needed. How about we ask for more opinions on gitter or something?

@aryairani
Copy link
Contributor Author

100% agreement. I meant to go back and say that short-circuiting would probably be more efficient in my use case; since the effects typically involve extra throwaway computation.

@aryairani
Copy link
Contributor Author

@kailuowang I was mistaken when I said scalaz doesn't short-circuit; it does:

scala> import scalaz._, Scalaz._
import scalaz._
import Scalaz._

scala> List(Some(true), None).anyM(identity)
res0: Option[Boolean] = Some(true)

scala> List(Some(true), None).allM(identity)
res1: Option[Boolean] = None

I'll redo the PR when I get a chance.

@aryairani aryairani closed this Aug 4, 2017
@kailuowang
Copy link
Contributor

err. not sure if you need to close this PR. If you replace with the implementation I gave it shortcircuit and pass the tests.

@aryairani
Copy link
Contributor Author

Ok, I wasn't sure if I should create a new one, or rebase or what.

@aryairani aryairani reopened this Aug 6, 2017
* }}}
*/
def forallM[G[_], A](fa: F[A])(p: A => G[Boolean])(implicit G: Monad[G]): G[Boolean] = {
val src = Foldable.Source.fromFoldable(fa)(self)
Copy link
Contributor

Choose a reason for hiding this comment

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

This isn't being used right.

Copy link
Contributor Author

@aryairani aryairani Aug 7, 2017

Choose a reason for hiding this comment

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

I meant to delete line 393, which isn't used, but do you want to elaborate?

Copy link
Contributor

@johnynek johnynek left a comment

Choose a reason for hiding this comment

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

👍

Copy link
Contributor

@kailuowang kailuowang left a comment

Choose a reason for hiding this comment

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

awesome! thanks!

@kailuowang kailuowang merged commit 272c684 into typelevel:master Aug 7, 2017
@kailuowang kailuowang added this to the 1.0.0-RC1 milestone Aug 7, 2017
@aryairani aryairani deleted the existsM-forallM branch August 7, 2017 15:11
@aryairani
Copy link
Contributor Author

I will add an example to the tut docs. Sorry I didn't think of it sooner.

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

Successfully merging this pull request may close these issues.

4 participants