package tf.bug.example import java.io.File import cats._ import cats.data._ import cats.implicits._ import cats.effect.IO import tf.bug.cataquack.{IORaw, Raw, Read, Storage} import tf.bug.cataquack.implicits._ import scala.io.Source object Example { type StringIORaw[T] = IORaw[String, T] type ReadString[T] = Read[String, T] def main(args: Array[String]): Unit = { val f: File = new File("counter.txt") val s: Storage[StringIORaw, ReadString] = new Storage[StringIORaw, ReadString] { override def query[T](key: String): StringIORaw[T] = IO { val s = Source.fromFile(f).getLines() s.find(_.startsWith(key ++ " ")) match { case Some(l) => Raw[String, T](l.drop(key.length + 1)) case None => throw new IllegalArgumentException(s"No such key: $key") } } /** Type like IO[List], Id, etc */ override type Output[T] = IO[T] override def execute[T: ReadString](f: StringIORaw[T]): Output[T] = f.map(_.read) } val count = readCount(s) val desc = readDescription(s) val pr = for { c <- count d <- desc } yield println(s"${d.read}: ${c.read}") pr.unsafeRunSync() } case class Counter(n: Long) case class Description(n: String) def readCount[F[_]: Functor, C[_]](s: Storage[F, C]): F[Long] = { s.query[Long]("count") } def readDescription[F[_]: Functor, C[_]](s: Storage[F, C]): F[String] = { s.query[String]("desc") } implicit def readStringLong: Read[String, Long] = (i: String) => i.toLong implicit def stringIORawFunctor: Functor[StringIORaw] = new Functor[StringIORaw] { override def map[A, B](fa: StringIORaw[A])(f: A => B): StringIORaw[B] = fa.map(a => rawFunctor[String].map(a)(f)) } }