From 21261f60cefbed64b92f8623cf0a893b7278200f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Miguel=20Mej=C3=ADa=20Su=C3=A1rez?= Date: Sat, 22 Jan 2022 19:10:48 -0500 Subject: [PATCH 1/5] Add F[Boolean] syntax --- js/src/main/scala/mouse/package.scala | 1 + .../src/main/scala/mouse/package.scala | 1 + .../src/main/scala/mouse/package.scala | 1 + .../scala-2/src/main/scala/mouse/all.scala | 17 +++--- .../scala-3/src/main/scala/mouse/all.scala | 17 +++--- shared/src/main/scala/mouse/fboolean.scala | 39 +++++++++++++ .../scala/mouse/FBooleanSyntaxTests.scala | 56 +++++++++++++++++++ 7 files changed, 116 insertions(+), 16 deletions(-) create mode 100644 shared/src/main/scala/mouse/fboolean.scala create mode 100644 shared/src/test/scala/mouse/FBooleanSyntaxTests.scala diff --git a/js/src/main/scala/mouse/package.scala b/js/src/main/scala/mouse/package.scala index 258ead0e..fdffc907 100644 --- a/js/src/main/scala/mouse/package.scala +++ b/js/src/main/scala/mouse/package.scala @@ -4,6 +4,7 @@ package object mouse extends MouseFunctions { object anyf extends AnyFSyntax object boolean extends BooleanSyntax object double extends DoubleSyntax + object fboolean extends FBooleanSyntax object feither extends FEitherSyntax object fnested extends FNestedSyntax object foption extends FOptionSyntax diff --git a/jvm/src/main/scala-2/src/main/scala/mouse/package.scala b/jvm/src/main/scala-2/src/main/scala/mouse/package.scala index a2d00ca1..9571b8af 100644 --- a/jvm/src/main/scala-2/src/main/scala/mouse/package.scala +++ b/jvm/src/main/scala-2/src/main/scala/mouse/package.scala @@ -4,6 +4,7 @@ package object mouse extends MouseFunctions { object anyf extends AnyFSyntax object boolean extends BooleanSyntax object double extends DoubleSyntax + object fboolean extends FBooleanSyntax object feither extends FEitherSyntax object fnested extends FNestedSyntax object foption extends FOptionSyntax diff --git a/jvm/src/main/scala-3/src/main/scala/mouse/package.scala b/jvm/src/main/scala-3/src/main/scala/mouse/package.scala index ffa8cbb9..a95604bd 100644 --- a/jvm/src/main/scala-3/src/main/scala/mouse/package.scala +++ b/jvm/src/main/scala-3/src/main/scala/mouse/package.scala @@ -4,6 +4,7 @@ package object mouse extends MouseFunctions { object anyf extends AnyFSyntax object boolean extends BooleanSyntax object double extends DoubleSyntax + object fboolean extends FBooleanSyntax object feither extends FEitherSyntax object fnested extends FNestedSyntax object foption extends FOptionSyntax diff --git a/shared/src/main/scala-2/src/main/scala/mouse/all.scala b/shared/src/main/scala-2/src/main/scala/mouse/all.scala index 7ffd60f4..cdc328d3 100644 --- a/shared/src/main/scala-2/src/main/scala/mouse/all.scala +++ b/shared/src/main/scala-2/src/main/scala/mouse/all.scala @@ -3,16 +3,17 @@ package mouse trait AllSharedSyntax extends AnySyntax with AnyFSyntax - with OptionSyntax with BooleanSyntax - with StringSyntax - with TrySyntax - with IntSyntax - with LongSyntax with DoubleSyntax - with PartialFunctionLift - with MapSyntax - with FOptionSyntax + with FBooleanSyntax with FEitherSyntax with FNestedSyntax + with FOptionSyntax + with IntSyntax + with LongSyntax + with MapSyntax + with OptionSyntax + with PartialFunctionLift + with StringSyntax + with TrySyntax with TupleSyntax diff --git a/shared/src/main/scala-3/src/main/scala/mouse/all.scala b/shared/src/main/scala-3/src/main/scala/mouse/all.scala index d1723c87..66201cae 100644 --- a/shared/src/main/scala-3/src/main/scala/mouse/all.scala +++ b/shared/src/main/scala-3/src/main/scala/mouse/all.scala @@ -3,15 +3,16 @@ package mouse trait AllSharedSyntax extends AnySyntax with AnyFSyntax - with OptionSyntax with BooleanSyntax - with StringSyntax - with TrySyntax - with IntSyntax - with LongSyntax with DoubleSyntax - with PartialFunctionLift - with MapSyntax - with FOptionSyntax + with FBooleanSyntax with FEitherSyntax with FNestedSyntax + with FOptionSyntax + with IntSyntax + with LongSyntax + with MapSyntax + with OptionSyntax + with PartialFunctionLift + with StringSyntax + with TrySyntax diff --git a/shared/src/main/scala/mouse/fboolean.scala b/shared/src/main/scala/mouse/fboolean.scala new file mode 100644 index 00000000..af503da8 --- /dev/null +++ b/shared/src/main/scala/mouse/fboolean.scala @@ -0,0 +1,39 @@ +package mouse + +import cats.{Functor, Monad} + +trait FBooleanSyntax { + implicit final def FBooleanSyntaxMouse[F[_]](fBoolean: F[Boolean]): FBooleanOps[F] = + new FBooleanOps[F](fBoolean) +} + +final class FBooleanOps[F[_]](private val fBoolean: F[Boolean]) extends AnyVal { + + /** + * Transforms this `F[Boolean]` by negating the `Boolean` + */ + def not(implicit F: Functor[F]): F[Boolean] = + F.map(fBoolean)(b => !b) + + /** + * Behaves like `&&` but inside the `F` context. + * + * Wont evaluate `other` unless this evaluates to `true` + */ + def andM(other: => F[Boolean])(implicit F: Monad[F]): F[Boolean] = + F.flatMap(fBoolean) { + case false => F.pure(false) + case true => other + } + + /** + * Behaves like `||` but inside the `F` context. + * + * Wont evaluate `other` unless this evaluates to `false` + */ + def orM(other: => F[Boolean])(implicit F: Monad[F]): F[Boolean] = + F.flatMap(fBoolean) { + case true => F.pure(true) + case false => other + } +} diff --git a/shared/src/test/scala/mouse/FBooleanSyntaxTests.scala b/shared/src/test/scala/mouse/FBooleanSyntaxTests.scala new file mode 100644 index 00000000..102a1bb0 --- /dev/null +++ b/shared/src/test/scala/mouse/FBooleanSyntaxTests.scala @@ -0,0 +1,56 @@ +package mouse + +import cats.{Eval, Id} + +class FBooleanSyntaxTests extends MouseSuite { + test("FBooleanSyntax.not") { + assertEquals(Id(true).not, Id(false)) + assertEquals(Id(false).not, Id(true)) + } + + test("FBooleanSyntax.andM") { + // Boolean logic. + assertEquals(Id(true).andM(Id(true)), Id(true)) + assertEquals(Id(true).andM(Id(false)), Id(false)) + assertEquals(Id(false).andM(Id(true)), Id(false)) + assertEquals(Id(false).andM(Id(false)), Id(false)) + + // Short-circuit. + var evalWasEvaluated = false + var functionWasCalled = false + def other = { + functionWasCalled = true + Eval.later { + evalWasEvaluated = true + true + } + } + + Eval.now(false).andM(other) + assertEquals(evalWasEvaluated, false) + assertEquals(functionWasCalled, false) + } + + test("FBooleanSyntax.orM") { + // Boolean logic. + assertEquals(Id(true).orM(Id(true)), Id(true)) + assertEquals(Id(true).orM(Id(false)), Id(true)) + assertEquals(Id(false).orM(Id(true)), Id(true)) + assertEquals(Id(false).orM(Id(false)), Id(false)) + + // Short-circuit. + var evalWasEvaluated = false + var functionWasCalled = false + def other = { + functionWasCalled = true + Eval.later { + evalWasEvaluated = true + true + } + } + + Eval.now(true).orM(other) + assertEquals(evalWasEvaluated, false) + assertEquals(functionWasCalled, false) + } +} From d63f9d63d3e5c8fa4a7e098d4d5ba00f6b9717e5 Mon Sep 17 00:00:00 2001 From: Ben Hutchison Date: Wed, 26 Jan 2022 12:46:45 +1100 Subject: [PATCH 2/5] Apply suggestions from code review Co-authored-by: Daniel Esik --- shared/src/main/scala/mouse/fboolean.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shared/src/main/scala/mouse/fboolean.scala b/shared/src/main/scala/mouse/fboolean.scala index af503da8..219a4d5d 100644 --- a/shared/src/main/scala/mouse/fboolean.scala +++ b/shared/src/main/scala/mouse/fboolean.scala @@ -20,7 +20,7 @@ final class FBooleanOps[F[_]](private val fBoolean: F[Boolean]) extends AnyVal { * * Wont evaluate `other` unless this evaluates to `true` */ - def andM(other: => F[Boolean])(implicit F: Monad[F]): F[Boolean] = + def andM(other: => F[Boolean])(implicit F: FlatMap[F]): F[Boolean] = F.flatMap(fBoolean) { case false => F.pure(false) case true => other @@ -31,7 +31,7 @@ final class FBooleanOps[F[_]](private val fBoolean: F[Boolean]) extends AnyVal { * * Wont evaluate `other` unless this evaluates to `false` */ - def orM(other: => F[Boolean])(implicit F: Monad[F]): F[Boolean] = + def orM(other: => F[Boolean])(implicit F: FlatMap[F]): F[Boolean] = F.flatMap(fBoolean) { case true => F.pure(true) case false => other From dafc503fe5f7b87d2eec661a971f91ad859901ee Mon Sep 17 00:00:00 2001 From: Ben Hutchison Date: Wed, 26 Jan 2022 12:54:25 +1100 Subject: [PATCH 3/5] Fix imports for FlatMap change --- shared/src/main/scala/mouse/fboolean.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/src/main/scala/mouse/fboolean.scala b/shared/src/main/scala/mouse/fboolean.scala index 219a4d5d..b71b50d7 100644 --- a/shared/src/main/scala/mouse/fboolean.scala +++ b/shared/src/main/scala/mouse/fboolean.scala @@ -1,6 +1,6 @@ package mouse -import cats.{Functor, Monad} +import cats.{Functor, FlatMap} trait FBooleanSyntax { implicit final def FBooleanSyntaxMouse[F[_]](fBoolean: F[Boolean]): FBooleanOps[F] = From ac55adb552e02f0a419d6b558f3aa5f87a57acfe Mon Sep 17 00:00:00 2001 From: Ben Hutchison Date: Wed, 26 Jan 2022 12:57:40 +1100 Subject: [PATCH 4/5] formatting --- shared/src/main/scala/mouse/fboolean.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/src/main/scala/mouse/fboolean.scala b/shared/src/main/scala/mouse/fboolean.scala index b71b50d7..a2e3e497 100644 --- a/shared/src/main/scala/mouse/fboolean.scala +++ b/shared/src/main/scala/mouse/fboolean.scala @@ -1,6 +1,6 @@ package mouse -import cats.{Functor, FlatMap} +import cats.{FlatMap, Functor} trait FBooleanSyntax { implicit final def FBooleanSyntaxMouse[F[_]](fBoolean: F[Boolean]): FBooleanOps[F] = From 123697d281fa0260f8f01555b230fef699f2587b Mon Sep 17 00:00:00 2001 From: Ben Hutchison Date: Wed, 26 Jan 2022 13:09:04 +1100 Subject: [PATCH 5/5] Revert Flatmap to Monad --- shared/src/main/scala/mouse/fboolean.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/shared/src/main/scala/mouse/fboolean.scala b/shared/src/main/scala/mouse/fboolean.scala index a2e3e497..af503da8 100644 --- a/shared/src/main/scala/mouse/fboolean.scala +++ b/shared/src/main/scala/mouse/fboolean.scala @@ -1,6 +1,6 @@ package mouse -import cats.{FlatMap, Functor} +import cats.{Functor, Monad} trait FBooleanSyntax { implicit final def FBooleanSyntaxMouse[F[_]](fBoolean: F[Boolean]): FBooleanOps[F] = @@ -20,7 +20,7 @@ final class FBooleanOps[F[_]](private val fBoolean: F[Boolean]) extends AnyVal { * * Wont evaluate `other` unless this evaluates to `true` */ - def andM(other: => F[Boolean])(implicit F: FlatMap[F]): F[Boolean] = + def andM(other: => F[Boolean])(implicit F: Monad[F]): F[Boolean] = F.flatMap(fBoolean) { case false => F.pure(false) case true => other @@ -31,7 +31,7 @@ final class FBooleanOps[F[_]](private val fBoolean: F[Boolean]) extends AnyVal { * * Wont evaluate `other` unless this evaluates to `false` */ - def orM(other: => F[Boolean])(implicit F: FlatMap[F]): F[Boolean] = + def orM(other: => F[Boolean])(implicit F: Monad[F]): F[Boolean] = F.flatMap(fBoolean) { case true => F.pure(true) case false => other