Skip to content

Instantly share code, notes, and snippets.

@yasuabe
Last active October 5, 2019 13:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yasuabe/584798aea7807bd9d4e834b4ab4e92cb to your computer and use it in GitHub Desktop.
Save yasuabe/584798aea7807bd9d4e834b4ab4e92cb to your computer and use it in GitHub Desktop.
Iota demo. Applied to cats free monad sample.
import cats.data.{State, Chain}
import cats.free.Free
import cats.~>
import iota.TListK.:::
import iota.{CopK, TNilK}
sealed trait Interact[A]
case class Ask(prompt: String) extends Interact[String]
case class Tell(msg: String) extends Interact[Unit]
sealed trait DataOp[A]
case class AddCat(a: String) extends DataOp[Unit]
case class GetAllCats() extends DataOp[List[String]]
sealed trait KVStoreOp[A]
case class GetCat(k: String) extends KVStoreOp[Option[String]]
case class PutCat(k: String, v: String) extends KVStoreOp[Unit]
type CatsApp[A] = CopK[Interact ::: DataOp ::: KVStoreOp ::: TNilK, A]
import cats.free.Free.inject
import scala.language.higherKinds
class Interacts[G[α] <: iota.CopK[_, α]](implicit I: CopK.Inject[Interact, G]) {
def ask(prompt: String): Free[G, String] = inject[Interact, G](Ask(prompt))
def tell(msg: String): Free[G, Unit] = inject[Interact, G](Tell(msg))
}
object Interacts {
implicit def interacts[F[α] <: iota.CopK[_, α]](implicit I: CopK.Inject[Interact, F]): Interacts[F] =
new Interacts[F]
}
class DataSource[F[α] <: iota.CopK[_, α]](implicit I: CopK.Inject[DataOp, F]) {
def addCat(a: String): Free[F, Unit] = inject[DataOp, F](AddCat(a))
def getAllCats: Free[F, List[String]] = inject[DataOp, F](GetAllCats())
}
object DataSource {
implicit def dataSource[F[α] <: iota.CopK[_, α]](implicit I: CopK.Inject[DataOp, F]): DataSource[F] =
new DataSource[F]
}
class KVStore[F[α] <: iota.CopK[_, α]](implicit I: CopK.Inject[KVStoreOp, F]) {
def getCat(k: String): Free[F, Option[String]] = inject[KVStoreOp, F](GetCat(k))
def putCat(k: String, v: String): Free[F, Unit] = inject[KVStoreOp, F](PutCat(k, v))
}
object KVStore {
implicit def kvStore[F[α] <: iota.CopK[_, α]](implicit I: CopK.Inject[KVStoreOp, F]): KVStore[F] =
new KVStore[F]
}
object CatsService {
def doSomething[A](implicit I: Interacts[CatsApp], D: DataSource[CatsApp], K: KVStore[CatsApp])
: Free[CatsApp, Unit] = {
for {
cat <- I.ask("kitty's name?")
_ <- D.addCat(cat)
s <- K.getCat(cat)
_ <- s.fold(K.putCat("name", cat))(_ => Free.pure(()))
all <- D.getAllCats
_ <- I.tell(all.toString)
} yield ()
}
}
type Operations[T] = State[Chain[Any], T]
import State.modify
def add[T](fa: Any)(f: => T = ()): Operations[T] =
modify[Chain[Any]](_ :+ fa).map(_ => f)
implicit val kvToStateInterpreter: Interact ~> Operations =
new (Interact ~> Operations) {
override def apply[A](fa: Interact[A]): Operations[A] = fa match {
case Ask(_) => add(fa)("mike")
case Tell(_) => add(fa)()
}
}
implicit val dataOpStateIntpr: DataOp ~> Operations =
new (DataOp ~> Operations) {
override def apply[A](fa: DataOp[A]) = fa match {
case AddCat(_) => add(fa)()
case GetAllCats() => add(fa)(List("kuro", "tama", "uni"))
}
}
implicit val kbStoreStateIntpr: KVStoreOp ~> Operations =
new (KVStoreOp ~> Operations) {
override def apply[A](fa: KVStoreOp[A]) = fa match {
case PutCat(_, _) => add(fa)()
case GetCat(_) => add(fa)(None)
}
}
val catAppStateInterpreter: CatsApp ~> Operations = CopK.FunctionK.of(
kvToStateInterpreter, dataOpStateIntpr, kbStoreStateIntpr)
CatsService.doSomething.foldMap(catAppStateInterpreter).run(Chain.empty[Any]).value
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment