From 34f5a2612ac06d1c3d2bbd2e27390ee0e46ade80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Derosiaux?= Date: Tue, 12 Jun 2018 22:07:42 +0200 Subject: [PATCH] Add empty to State and StateT objects Co-authored-by: Lars Hupel --- core/src/main/scala/cats/data/IndexedStateT.scala | 12 +++++++++++- core/src/main/scala/cats/data/package.scala | 2 +- .../test/scala/cats/tests/IndexedStateTSuite.scala | 11 +++++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/core/src/main/scala/cats/data/IndexedStateT.scala b/core/src/main/scala/cats/data/IndexedStateT.scala index 1a9fe1278fb..c7c8721fc23 100644 --- a/core/src/main/scala/cats/data/IndexedStateT.scala +++ b/core/src/main/scala/cats/data/IndexedStateT.scala @@ -203,7 +203,7 @@ private[data] trait CommonStateTConstructors { IndexedStateT(s => F.pure((s, s))) } -object IndexedStateT extends IndexedStateTInstances with CommonStateTConstructors { +object IndexedStateT extends IndexedStateTInstances with CommonStateTConstructors0 { def apply[F[_], SA, SB, A](f: SA => F[(SB, A)])(implicit F: Applicative[F]): IndexedStateT[F, SA, SB, A] = new IndexedStateT(F.pure(f)) @@ -223,6 +223,11 @@ object IndexedStateT extends IndexedStateTInstances with CommonStateTConstructor IndexedStateT(_ => F.map(fsb)(s => (s, ()))) } +private[data] trait CommonStateTConstructors0 extends CommonStateTConstructors { + def empty[F[_], S, A](implicit A: Monoid[A], F: Applicative[F]): IndexedStateT[F, S, S, A] = + pure(A.empty) +} + private[data] abstract class StateTFunctions extends CommonStateTConstructors { def apply[F[_], S, A](f: S => F[(S, A)])(implicit F: Applicative[F]): StateT[F, S, A] = IndexedStateT(f) @@ -299,6 +304,11 @@ private[data] abstract class StateFunctions { */ def pure[S, A](a: A): State[S, A] = State(s => (s, a)) + /** + * Return `A`'s empty monoid value and maintain the input state. + */ + def empty[S, A: Monoid]: State[S, A] = pure(Monoid[A].empty) + /** * Modify the input state and return Unit. */ diff --git a/core/src/main/scala/cats/data/package.scala b/core/src/main/scala/cats/data/package.scala index 218300dbc00..77c60f0b8f4 100644 --- a/core/src/main/scala/cats/data/package.scala +++ b/core/src/main/scala/cats/data/package.scala @@ -49,7 +49,7 @@ package object data { * context along with the `A` value. */ type StateT[F[_], S, A] = IndexedStateT[F, S, S, A] - object StateT extends StateTFunctions + object StateT extends StateTFunctions with CommonStateTConstructors0 type State[S, A] = StateT[Eval, S, A] object State extends StateFunctions diff --git a/tests/src/test/scala/cats/tests/IndexedStateTSuite.scala b/tests/src/test/scala/cats/tests/IndexedStateTSuite.scala index 5134563a8cd..88589251c35 100644 --- a/tests/src/test/scala/cats/tests/IndexedStateTSuite.scala +++ b/tests/src/test/scala/cats/tests/IndexedStateTSuite.scala @@ -55,6 +55,17 @@ class IndexedStateTSuite extends CatsSuite { } } + test("State.empty, StateT.empty and IndexedStateT.empty are consistent"){ + forAll { (s: String) => + val state: State[String, Int] = State.empty + val stateT: State[String, Int] = StateT.empty + val indexedStateT: State[String, Int] = IndexedStateT.empty + + state.run(s) should === (stateT.run(s)) + state.run(s) should === (indexedStateT.run(s)) + } + } + test("State.get, StateT.get and IndexedStateT.get are consistent") { forAll{ (s: String) => val state: State[String, String] = State.get