通过理解和应用纯净,与ReaderT一起编写

时间:2019-03-23 13:56:23

标签: scala monads composition monad-transformers scala-cats

以下是返回ReaderTEither作为返回类型的函数:

  import cats.data.{ReaderT}
  type FailFast[A] = Either[List[String], A]

  def getValue(name: String):ReaderT[FailFast, Map[String, String], String] =
    ReaderT((map) => map.get(name)
      .toRight(List(s"$name field not specified")))

  def nonNullable(name: String)(data: String): FailFast[String] =
    Right(data).ensure(List(s"$name cannot be nullable"))(_ != null)

  def nonBlank(name: String)(data: String): FailFast[String] =
    Right(data).ensure(List(s"$name cannot be blank"))(_.nonEmpty)

以下是这些功能的组合,效果很好:

  def readNotEmptyValue(name: String): ReaderT[FailFast, Map[String, String], String] =
    for {
      value <- getValue(name)
      _ <- ReaderT((_:Map[String, String]) => nonNullable(name)(value))
      res <- ReaderT((_:Map[String, String]) => nonBlank(name)(value))
    } yield res

我想摆脱此ReaderT.apply调用,并通过应用纯文本编写一些内容:

  type Q[A] = ReaderT[FailFast, Map[String, String], A]
  import cats.syntax.applicative._
  import cats.instances.either._
  def readNotEmptyValue(name: String): ReaderT[FailFast, Map[String, String], String] =
    for {
      value <- getValue(name)
      _ <- nonBlank(name)(value).pure[Q]
      res <- nonBlank(name)(value).pure[Q]
    } yield res.right.get

不幸的是,最后的解决方案不适用于否定案例。我可以确定使用match进行检查,天气是Right还是Left

但是有一种方法可以使它纯净地构成,并最大程度地减少人工工作。如何正确执行?

1 个答案:

答案 0 :(得分:2)

您可以使用EitherOps.liftTo代替Applicative.pure来消除ReaderT.apply的详细信息:

def readNotEmptyValue(name: String): ReaderT[FailFast, Map[String, String], String] = 
  for {
    value <- getValue(name)
    _ <- nonBlank(name)(value).liftTo[Q]
    res <- nonBlank(name)(value).liftTo[Q]
  } yield res

否则,您仍在处理FailFast[String]而不是String的实例,并且如果要尝试从FailFast中提取值,则无法解决。