Last active
August 12, 2021 16:28
-
-
Save igstan/05ba68cdb6f90674b6ba08c6bf608e6c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import cats.implicits._ | |
import cats.Monad | |
import cats.data.State | |
// | |
// Two capability/tagless final traits: Foo & Bar | |
// | |
trait Foo[F[_]] { | |
def foo: F[Unit] | |
} | |
trait Bar[F[_]] { | |
def bar: F[Unit] | |
} | |
// | |
// Two isolated stateful implementations. Each of them counts the number | |
// of calls to that particular method. | |
// | |
object CountedFoo extends Foo[State[Int, *]] { | |
override def foo: State[Int, Unit] = | |
State.modify(_ + 1) | |
} | |
object CountedBar extends Bar[State[Int, *]] { | |
override def bar: State[Int, Unit] = | |
State.modify(_ + 1) | |
} | |
object StateComposition { | |
// Mixed usage of the two traits. | |
def abstractUsage[F[_]: Monad](foo: Foo[F], bar: Bar[F]): F[Unit] = | |
foo.foo >> foo.foo >> foo.foo >> bar.bar | |
def main(args: Array[String]): Unit = { | |
// | |
// Q: how would you compose CountedFoo and CountedBar so that they | |
// can be used together inside `abstractUsage`. | |
// | |
type Composed[A] = ??? | |
def composed: Foo[Composed] with Bar[Composed] = ??? | |
val result = abstractUsage(composed, composed) | |
} | |
// I was thinking of doing something like this, but I'm wondering what's | |
// a better way of doing it. | |
final case class Counters(foo: Int, bar: Int) | |
type ComposedCounters[A] = State[Counters, A] | |
object Composed extends Foo[ComposedCounters] with Bar[ComposedCounters] { | |
override def foo: ComposedCounters[Unit] = | |
State.modify { counters => | |
val fooState = CountedFoo.foo.runS(counters.foo).value | |
counters.copy(foo = fooState) | |
} | |
override def bar: ComposedCounters[Unit] = | |
State.modify { counters => | |
val barState = CountedBar.bar.runS(counters.bar).value | |
counters.copy(bar = barState) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Improved implementation of
Composed
usingIndexedStateT.transformS
: