0

我有一个用 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)
            }
        }
    }

哪个效果很好,但我对添加 State monad 之前并不满意,代码更加清晰,即:

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

我想知道如何让 State 与 Kleisli 合作?这样所有的单子都会像一个一样一起工作?

而不是logger意志的作用i2ff2s功能,也能在里面起作用?

4

1 回答 1

0

好的,取得了一些进展,现在代码是:

    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)
            }
        }
    }
于 2019-04-11T04:10:01.170 回答