我有以下方法:
trait Tr[F[_]]{
def getSet(): F[Set[String]]
def checksum(): F[Long]
def value(): F[String]
def doRun(v: String, c: Long, s: Set[String]): F[Unit]
}
现在我想写以下内容以供理解:
import cats._
import cats.data.OptionT
import cats.implicits._
def fcmprhn[F[_]: Monad](F: Tr[F]): OptionT[F, Unit] =
for {
set <- OptionT {
F.getSet() map { s =>
if(s.nonEmpty) Some(s) else None
}
}
checksum <- OptionT.liftF(F.checksum())
v <- OptionT.liftF(F.value())
_ <- OptionT.liftF(F.doRun(v, checksum, set))
//can be lots of OptionT.liftF here
} yield ()
如您所见,OptionT
样板太多了。有办法避免吗?
我认为我可以利用F ~> OptionT[F, ?]
。你能建议点什么吗?
答案 0 :(得分:1)
一种方法可能是将理解力的“仅F”部分嵌套在单个background-image: url('http://unsplash.it/1200x800'), linear-gradient(red, transparent);
background-size: contain;
background-repeat: no-repeat;
background-position: right;
中:
liftF
答案 1 :(得分:1)
您可以改为以“ mtl样式”编写它。 mtl-style指的是haskell中的mtl库,但实际上它只是意味着我们将效果编码为具有抽象效果OptionT[F, ?]
的函数,而不是将效果编码为值(即F[_]
),并赋予{{ 1}}使用类型类的功能。这意味着不必使用F
作为返回类型,而只需使用OptionT[F, Unit]
作为我们的返回类型,因为F[Unit]
必须能够处理错误。
这使编写类似您的代码的过程稍微容易一些,但是当您向堆栈中添加monad转换器时,效果会得到放大。现在,您只需要举起一次,但是如果将来需要F
,该怎么办。使用mtl-style,您需要做的就是添加另一个类型类约束。
这是用mtl样式编写的代码:
StateT[OptionT[F, ?], S, Unit]
现在,当您运行程序时,可以将def fcmprhn[F[_]](F: Tr[F])(implicit E: MonadError[F, Unit]): F[Unit] =
for {
set <- OptionT {
F.getSet() flatMap { s =>
if(s.nonEmpty) E.pure(s) else E.raiseError(())
}
}
checksum <- F.checksum()
v <- F.value()
_ <- F.doRun(v, checksum, set)
} yield ()
指定为类似于F[_]
之前的样子:
OptionT[F, ?]