I'm having an example for a logger wrapped with State monad:
val logger = Logger(LoggerFactory.getLogger(this.getClass))
def logState[A](s:IO[Unit], a:A): State[List[IO[Unit]], A] = State[List[IO[Unit]], A]{ logs =>
(logs :+ s, a)
}
type Valid[A] = Exception \/ A
def i2f(i:Int): Valid[BigDecimal] = if (i >= 0) BigDecimal(i).right else (new RuntimeException("Input is smaller then 0")).left
def f2s(f: Valid[BigDecimal]): Valid[String] = f match {
case \/-(f1) => f1.toString.right
case -\/(e) => e.left
}
val comp: Int => State[List[IO[Unit]], Valid[String]] = i => for{
f <- logState(IO{ logger.info(s" => i2f($i)")}, i2f(i))
s <- logState(IO{ logger.info(s" => f2s($f)")}, f2s(f))
} yield s
comp(2)(List.empty) match {
case (logs, a) => {
logs.foreach(_.unsafePerformIO())
a match {
case \/-(s) => println(s"Finally we get: ${s}")
case -\/(e) => println(e.getMessage)
}
}
}
Which works well, but I'm not satisfy with as before I adding State monad, the code was much more clear which was:
type Valid[A] = Exception \/ A
def i2f: Kleisli[Valid, Int, BigDecimal] = Kleisli { i =>
if (i >= 0) BigDecimal(i).right else (new RuntimeException("Input is smaller then 0")).left
}
def f2s: Kleisli[Valid, BigDecimal, String] = Kleisli { f =>
f.toString().right
}
def comp: Kleisli[Valid, Int, String] = i2f andThen f2s
comp(2) match {
case \/-(s) => println(s"Finally we get: ${s}")
case -\/(e) => println(e.getMessage)
}
I'm wondering how let State to work with Kleisli? so that all monads will be working together likes one?
And not the logger
will works out of i2f
and f2s
functions, but also are able to work inside?
All right, got some progress, now the code been: