以下函数返回 ReaderT
和 Either
作为返回类型:
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
调用,并通过 applicative pure 编写一些东西:
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
。
但是有没有一种方法可以纯粹地并最小化手动工作来编写它。如何正确地做到这一点?
最佳答案
您可以使用 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
。
关于scala - 通过 for-compositional 和 applicative pure 来使用 Either 组合 ReaderT,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55314431/