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

whenM #4626

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft

whenM #4626

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions core/src/main/scala-2/cats/syntax/MonadOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ final class MonadOps[F[_], A](private val fa: F[A]) extends AnyVal {
def untilM_(p: F[Boolean])(implicit M: Monad[F]): F[Unit] = M.untilM_(fa)(p)
def iterateWhile(p: A => Boolean)(implicit M: Monad[F]): F[A] = M.iterateWhile(fa)(p)
def iterateUntil(p: A => Boolean)(implicit M: Monad[F]): F[A] = M.iterateUntil(fa)(p)
def whenM(p: F[Boolean])(implicit M: Monad[F]): F[Unit] = M.whenM(fa)(p)
def unlessM(p: F[Boolean])(implicit M: Monad[F]): F[Unit] = M.unlessM(fa)(p)
def flatMapOrKeep[A1 >: A](pfa: PartialFunction[A, F[A1]])(implicit M: Monad[F]): F[A1] =
M.flatMapOrKeep[A, A1](fa)(pfa)
}
16 changes: 16 additions & 0 deletions core/src/main/scala/cats/Monad.scala
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,20 @@ trait Monad[F[_]] extends FlatMap[F] with Applicative[F] {
tailRecM(branches.toList)(step)
}

/**
* Returns the given argument (mapped to Unit) if `cond` evaluates to `false`, otherwise,
* unit lifted into F.
*/
def unlessM[A](f: F[A])(cond: F[Boolean]): F[Unit] =
flatMap(cond)(bool => if (bool) unit else void(f))

/**
* Returns the given argument (mapped to Unit) if `cond` evaluates to `true`, otherwise,
* unit lifted into F.
*/
def whenM[A](f: F[A])(cond: F[Boolean]): F[Unit] =
flatMap(cond)(bool => if (bool) void(f) else unit)
Comment on lines +176 to +177
Copy link
Member

Choose a reason for hiding this comment

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

Just to promote Mouse, you may be interested to glance at this syntax
https://github.com/typelevel/mouse/blob/main/shared/src/main/scala/mouse/boolean.scala#L73
It covers whenA and unlessA for boolean values.


/**
* Modifies the `A` value in `F[A]` with the supplied function, if the function is defined for the value.
* Example:
Expand Down Expand Up @@ -204,6 +218,8 @@ object Monad {
def untilM_(cond: => F[Boolean]): F[Unit] = typeClassInstance.untilM_[A](self)(cond)
def iterateWhile(p: A => Boolean): F[A] = typeClassInstance.iterateWhile[A](self)(p)
def iterateUntil(p: A => Boolean): F[A] = typeClassInstance.iterateUntil[A](self)(p)
def whenM(cond: F[Boolean]): F[Unit] = typeClassInstance.whenM[A](self)(cond)
def unlessM(cond: F[Boolean]): F[Unit] = typeClassInstance.unlessM[A](self)(cond)
}
trait AllOps[F[_], A] extends Ops[F, A] with FlatMap.AllOps[F, A] with Applicative.AllOps[F, A] {
type TypeClassType <: Monad[F]
Expand Down
16 changes: 16 additions & 0 deletions tests/shared/src/test/scala/cats/tests/MonadSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,22 @@ class MonadSuite extends CatsSuite {
}
}

test("whenM should void when true") {
assert(List(1, 2).whenM(List(true)) == List((), ()))
}

test("whenM should unit when false") {
assert(List(1, 2).whenM(List(false)) == List(()))
}

test("unlessM should unit when true") {
assert(List(1, 2).unlessM(List(true)) == List(()))
}

test("unlessM should void when false") {
assert(List(1, 2).unlessM(List(false)) == List((), ()))
}

test("whileM_ stack safety") {
val (result, _) = increment.whileM_(StateT.inspect(i => !(i >= 50000))).run(0)
assert(result === 50000)
Expand Down
Loading