Skip to content

Instantly share code, notes, and snippets.

@phenan
Created March 26, 2022 03:48
Show Gist options
  • Save phenan/bc9946f0875691c8d3bb884d7e37378e to your computer and use it in GitHub Desktop.
Save phenan/bc9946f0875691c8d3bb884d7e37378e to your computer and use it in GitHub Desktop.
Free can be used as Eff
import cats.arrow.FunctionK
import cats.data.{ReaderWriterState}
import cats.free.Free
/* utilities for using free as eff */
extension [S[_], A] (free: Free[S, A]) {
def widenEffect[R[_]](using subtype: S[A] <:< R[A]): Free[R, A] = {
free.asInstanceOf[Free[R, A]]
}
}
infix type :|: [S1[_], S2[_]] = [T] =>> S1[T] | S2[T]
/* effect definitions */
enum ReaderEffect[S, T] {
case Ask[S]() extends ReaderEffect[S, S]
}
object ReaderEffect {
def ask[S]: Free[[T] =>> ReaderEffect[S, T], S] = Free.liftF(ReaderEffect.Ask[S]())
}
enum WriterEffect[S, T] {
case Tell[S](value: S) extends WriterEffect[S, Unit]
}
object WriterEffect {
def tell[S](value: S): Free[[T] =>> WriterEffect[S, T], Unit] = Free.liftF(WriterEffect.Tell(value))
}
/* domain logic */
type IntReaderEffect[T] = ReaderEffect[Int, T]
type IntWriterEffect[T] = WriterEffect[Int, T]
val logic: Free[IntReaderEffect :|: IntWriterEffect, Int] = for {
x <- ReaderEffect.ask[Int].widenEffect
_ <- WriterEffect.tell(x + 1).widenEffect
} yield x
/* effect compiler */
val compiler: FunctionK[IntReaderEffect :|: IntWriterEffect, [T] =>> ReaderWriterState[Int, List[Int], Unit, T]] = new FunctionK[IntReaderEffect :|: IntWriterEffect, [T] =>> ReaderWriterState[Int, List[Int], Unit, T]] {
override def apply[A](effect: ReaderEffect[Int, A] | WriterEffect[Int, A]): ReaderWriterState[Int, List[Int], Unit, A] = effect match {
case ReaderEffect.Ask() => ReaderWriterState.ask
case WriterEffect.Tell(value) => ReaderWriterState.tell(value :: Nil)
}
}
/* test */
object Main {
def main(args: Array[String]): Unit = {
val rws: ReaderWriterState[Int, List[Int], Unit, Int] = logic.foldMap(compiler)
val result: (List[Int], Unit, Int) = rws.runEmpty(100).value
println(result)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment