Как пусть Государство работает с Клейсли? - PullRequest
0 голосов
/ 10 апреля 2019

У меня есть пример для логгера, завернутого в монаду State:

    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)
            }
        }
    }

Что работает хорошо, но я не удовлетворен тем, что до того, как я добавил монаду State, код был гораздо более понятным:

    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)
    }

Мне интересно, как позволить государству работать с Клейсли? так что все монады будут работать вместе нравится один?

А не logger будет работать из i2f и f2s функций, но также сможет работать внутри?

1 Ответ

0 голосов
/ 11 апреля 2019

Хорошо, получил некоторый прогресс, теперь код был:

    implicit val ec =  scala.concurrent.ExecutionContext.global

    type Valid[A] = Exception \/ A
    type Report = List[IO[Unit]]
    type StateResultT[A] = StateT[Future, Report, A]

    implicit val StateResultBind: Bind[StateResultT] = new Bind[StateResultT] {
        override def bind[A, B](fa: StateResultT[A])(f: A => StateResultT[B]): StateResultT[B] = fa flatMap f
        override def map[A, B](fa: StateResultT[A])(f: A => B): StateResultT[B] = fa map f
    }

    def i2f: Kleisli[StateResultT, Int, Valid[BigDecimal]] = Kleisli{ i =>
        StateT { logs =>
            Future (
                    logs :+ IO(logger.debug("i2f")),
                    if (i >= 0) BigDecimal(i).right else (new RuntimeException("Input is smaller then 0")).left
            )
        }
    }

    def f2s: Kleisli[StateResultT, Valid[BigDecimal], (Report, Valid[String])] = Kleisli { s =>
        StateT { logs =>
            Future (
                logs :+ IO(logger.debug("f2s")),
                s match{
                    case \/-(f) => f.toString.right
                    case -\/(e) => e.left
                }
            )
        }
    }

    def comp: Kleisli[StateResultT, Int, Valid[String]] = i2f andThen f2s

    Await.result(comp(-2)(List.empty), Duration.Inf) match {
        case (logs, a) => {
            logs.foreach(_.unsafePerformIO())
            a match {
                case \/-(s) => println(s"Finally we get: ${s}")
                case -\/(e) => println(e.getMessage)
            }
        }
    }
...