scala - 堆叠 monads Writer 和 OptionT
问题描述
我有以下代码:
override def getStandsByUser(email: String): Try[Seq[Stand]] =
(for {
user <- OptionT(userService.findOneByEmail(email)): Try[Option[User]]
stands <- OptionT.liftF(standService.list()):[Try[List[Stand]]]
filtered = stands.filter(stand => user.stands.contains(stand.id))
} yield filtered).getOrElse(Seq())
}
我想在处理的每个阶段添加日志记录 - 所以我需要引入 writer monad 并将其与 monad 转换器 OptionT 堆叠。你能建议怎么做吗?
解决方案
最好的方法是将您的服务调用转换为使用cats-mtl
.
对于表示Try
或Option
您可以使用MonadError
,对于记录,您可以使用FunctorTell
. 现在我不知道你在userService
or中到底在做什么standService
,但我写了一些代码来演示结果可能是什么样子:
type Log = List[String]
//inside UserService
def findOneByEmail[F[_]](email: String)
(implicit F: MonadError[F, Error], W: FunctorTell[F, Log]): F[User] = ???
//inside StandService
def list[F[_]]()
(implicit F: MonadError[F, Error], W: FunctorTell[F, Log]): F[List[Stand]] = ???
def getStandsByUser[F[_]](email: String)
(implicit F: MonadError[F, Error], W: FunctorTell[F, Log]): F[List[Stand]] =
for {
user <- userService.findOneByEmail(email)
stands <- standService.list()
} yield stands.filter(stand => user.stands.contains(stand.id))
//here we actually run the function
val result =
getStandsByUser[WriterT[OptionT[Try, ?], Log, ?] // yields WriterT[OptionT[Try, ?], Log, List[Stand]]
.run // yields OptionT[Try, (Log, List[Stand])]
.value // yields Try[Option[(Log, List[Stand])]]
这样我们就可以避免所有对不同服务的调用liftF
并轻松组合我们的不同服务,即使它们在运行时会使用不同的 monad 转换器。
推荐阅读
- javascript - Vuex v-model 到对象状态字段
- java - 使用 WebView 加载时网站不可用
- mysql - Laravel 数据库连接被拒绝
- php - 如果页面来自我网站上的链接,如何仅允许访问该页面
- javascript - 未捕获的类型错误:cuadrito.getContext 不是 eventos.js:10 的函数
- visual-studio-code - 编译器 clang.exe 在 VSCode 上找不到标头
- c++ - 不同整数的数组相加
- java - Shell 脚本不作为 crontab 运行,而是手动运行
- python - 无法通过 OpenCV python 打开 Mac 网络摄像头
- reactjs - 在 VS Code 中配置 JSX 用户代码段