以下是返回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
调用,并通过应用纯文本编写一些内容:
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
。
但是有一种方法可以使它纯净地构成,并最大程度地减少人工工作。如何正确执行?
答案 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
中提取值,则无法解决。