diff --git a/jvm/src/main/scala-2.x/src/main/scala/mouse/package.scala b/jvm/src/main/scala-2.x/src/main/scala/mouse/package.scala index a2d00ca1..e5e9d6bf 100644 --- a/jvm/src/main/scala-2.x/src/main/scala/mouse/package.scala +++ b/jvm/src/main/scala-2.x/src/main/scala/mouse/package.scala @@ -3,6 +3,7 @@ package object mouse extends MouseFunctions { object any extends AnySyntax object anyf extends AnyFSyntax object boolean extends BooleanSyntax + object booleanf extends BooleanFSyntax object double extends DoubleSyntax object feither extends FEitherSyntax object fnested extends FNestedSyntax diff --git a/jvm/src/main/scala-3.x/src/main/scala/mouse/package.scala b/jvm/src/main/scala-3.x/src/main/scala/mouse/package.scala index ffa8cbb9..ce446b5c 100644 --- a/jvm/src/main/scala-3.x/src/main/scala/mouse/package.scala +++ b/jvm/src/main/scala-3.x/src/main/scala/mouse/package.scala @@ -3,6 +3,7 @@ package object mouse extends MouseFunctions { object any extends AnySyntax object anyf extends AnyFSyntax object boolean extends BooleanSyntax + object booleanf extends BooleanFSyntax object double extends DoubleSyntax object feither extends FEitherSyntax object fnested extends FNestedSyntax diff --git a/shared/src/main/scala-2.x/src/main/scala/mouse/all.scala b/shared/src/main/scala-2.x/src/main/scala/mouse/all.scala index 7ffd60f4..5df79863 100644 --- a/shared/src/main/scala-2.x/src/main/scala/mouse/all.scala +++ b/shared/src/main/scala-2.x/src/main/scala/mouse/all.scala @@ -5,6 +5,7 @@ trait AllSharedSyntax with AnyFSyntax with OptionSyntax with BooleanSyntax + with BooleanFSyntax with StringSyntax with TrySyntax with IntSyntax diff --git a/shared/src/main/scala-3.x/src/main/scala/mouse/all.scala b/shared/src/main/scala-3.x/src/main/scala/mouse/all.scala index d1723c87..5a47ecb1 100644 --- a/shared/src/main/scala-3.x/src/main/scala/mouse/all.scala +++ b/shared/src/main/scala-3.x/src/main/scala/mouse/all.scala @@ -5,6 +5,7 @@ trait AllSharedSyntax with AnyFSyntax with OptionSyntax with BooleanSyntax + with BooleanFSyntax with StringSyntax with TrySyntax with IntSyntax diff --git a/shared/src/main/scala/mouse/booleanf.scala b/shared/src/main/scala/mouse/booleanf.scala new file mode 100644 index 00000000..ced2bfe8 --- /dev/null +++ b/shared/src/main/scala/mouse/booleanf.scala @@ -0,0 +1,58 @@ +package mouse + +import cats.{Applicative, Functor, Monad} + +trait BooleanFSyntax { + + implicit final def booleanfSyntaxMouse[F[_]](fa: F[Boolean]): BooleanFOps[F] = new BooleanFOps(fa) +} + +final class BooleanFOps[F[_]](private val fa: F[Boolean]) extends AnyVal { + + def &&(fb: => F[Boolean])(implicit F: Monad[F]): F[Boolean] = + F.flatMap(fa) { + case true => fb + case false => F.pure(false) + } + + def &&(b: => Boolean)(implicit F: Functor[F]): F[Boolean] = + F.map(fa) { + case true => b + case false => false + } + + def ||(fb: => F[Boolean])(implicit F: Monad[F]): F[Boolean] = + F.flatMap(fa) { + case true => F.pure(true) + case false => fb + } + + def ||(b: => Boolean)(implicit F: Functor[F]): F[Boolean] = + F.map(fa) { + case true => true + case false => b + } + + def &(fb: F[Boolean])(implicit F: Applicative[F]): F[Boolean] = + F.ap(F.map(fa)(a => b => a && b))(fb) + + def &(b: Boolean)(implicit F: Functor[F]): F[Boolean] = + F.map(fa)(_ && b) + + def |(fb: F[Boolean])(implicit F: Applicative[F]): F[Boolean] = + F.ap(F.map(fa)(a => b => a || b))(fb) + + def |(b: Boolean)(implicit F: Functor[F]): F[Boolean] = + F.map(fa)(_ || b) + + def ^(fb: F[Boolean])(implicit F: Monad[F]): F[Boolean] = + F.flatMap(fa) { a => + F.flatMap(fb) { b => F.pure(a ^ b) } + } + + def ^(b: Boolean)(implicit F: Functor[F]): F[Boolean] = + F.map(fa) { _ ^ b } + + def unary_!(implicit F: Functor[F]): F[Boolean] = + F.map(fa)(!_) +} diff --git a/shared/src/test/scala/mouse/BooleanFSyntaxTest.scala b/shared/src/test/scala/mouse/BooleanFSyntaxTest.scala new file mode 100644 index 00000000..916e42bc --- /dev/null +++ b/shared/src/test/scala/mouse/BooleanFSyntaxTest.scala @@ -0,0 +1,64 @@ +package mouse + +import cats.instances.either._ +import cats.syntax.either._ + +class BooleanFSyntaxTest extends MouseSuite { + + test("BooleanFSyntax.&&.F") { + assertEquals(true.asRight[Int] && true.asRight[Int], Right(true)) + assertEquals(true.asRight[Int] && false.asRight[Int], Right(false)) + assertEquals(false.asRight[Int] && true.asRight[Int], Right(false)) + assertEquals(false.asRight[Int] && false.asRight[Int], Right(false)) + assertEquals(true.asRight[Unit] && ().asLeft[Boolean], Left(())) + assertEquals(().asLeft[Boolean] && false.asRight[Unit], Left(())) + } + + test("BooleanFSyntax.&&") { + assertEquals(true.asRight[Int] && true, Right(true)) + assertEquals(true.asRight[Int] && false, Right(false)) + assertEquals(false.asRight[Int] && true, Right(false)) + assertEquals(false.asRight[Int] && false, Right(false)) + assertEquals(().asLeft[Boolean] && false, Left(())) + } + + test("BooleanFSyntax.||.F") { + assertEquals(true.asRight[Int] || true.asRight[Int], Right(true)) + assertEquals(true.asRight[Int] || false.asRight[Int], Right(true)) + assertEquals(false.asRight[Int] || true.asRight[Int], Right(true)) + assertEquals(false.asRight[Int] || false.asRight[Int], Right(false)) + assertEquals(true.asRight[Unit] || ().asLeft[Boolean], Right(true)) + assertEquals(().asLeft[Boolean] || false.asRight[Unit], Left(())) + } + + test("BooleanFSyntax.||") { + assertEquals(true.asRight[Int] || true, Right(true)) + assertEquals(true.asRight[Int] || false, Right(true)) + assertEquals(false.asRight[Int] || true, Right(true)) + assertEquals(false.asRight[Int] || false, Right(false)) + assertEquals(().asLeft[Boolean] || false, Left(())) + } + + test("BooleanFSyntax.^.F") { + assertEquals(true.asRight[Int] ^ true.asRight[Int], Right(false)) + assertEquals(true.asRight[Int] ^ false.asRight[Int], Right(true)) + assertEquals(false.asRight[Int] ^ true.asRight[Int], Right(true)) + assertEquals(false.asRight[Int] ^ false.asRight[Int], Right(false)) + assertEquals(true.asRight[Unit] ^ ().asLeft[Boolean], Left(())) + assertEquals(().asLeft[Boolean] ^ false.asRight[Unit], Left(())) + } + + test("BooleanFSyntax.^") { + assertEquals(true.asRight[Int] ^ true, Right(false)) + assertEquals(true.asRight[Int] ^ false, Right(true)) + assertEquals(false.asRight[Int] ^ true, Right(true)) + assertEquals(false.asRight[Int] ^ false, Right(false)) + assertEquals(().asLeft[Boolean] ^ false, Left(())) + } + + test("BooleanFSyntax.!") { + assertEquals(!true.asRight[Int], Right(false)) + assertEquals(!false.asRight[Int], Right(true)) + assertEquals(!().asLeft[Boolean], Left(())) + } +}