如何使用 Kleisli 减少样板代码
How to reduce boilerplate with Kleisli
我按照书上的设计Functional and Reactive Domain Modeling
并且对于某些服务方法,它只将工作委托给存储层。有没有办法减少这个样板:
trait FeedbackServiceImpl extends FeedbackService {
override def saveTFE(feedback: TripFeedbackEvent) =
Kleisli[Future, Context, Either[String, Id]] { ctx => ctx.feedbackRepo.save(feedback) }
override def saveLFE(feedback: LibraryFeedbackEvent) =
Kleisli[Future, Context, Either[String, Id]] { ctx => ctx.feedbackRepo.save(feedback) }
override def findByUser(userId: Id) =
Kleisli[Future, Context, Seq[FeedbackEvent]] { ctx => ctx.feedbackRepo.findByUser(userId) }
override def all =
Kleisli[Future, Context, Seq[FeedbackEvent]] { ctx => ctx.feedbackRepo.all }
override def findByTip(tipId: Id) =
Kleisli[Future, Context, Seq[FeedbackEvent]] { ctx => ctx.feedbackRepo.findByTip(tipId) }
}
您能否只定义一个执行所有样板文件的函数?类似于:
def repo2Kleisli[T](f: Repo => Future[T]): Kleisli[Future, Context, T]
您甚至可以将其隐式化并将您的代码简化为:
override def saveTFE(feedback: TripFeedbackEvent) = (repo: Repo) => repo.save(feedback)
我们可以创建一个 组合器 :
private def kleisli[M[_], A](f: FeedbackRepository => M[A]) =
Kleisli.kleisli(f).local[Context](_.feedbackRepo)
因此我们得到了两件事:
- 通过帮助类型推断机制避免声明类型
- 避免使用
local
调用 ctx.feedbackRepo
所以我们可以使用:
trait Feedbacks {
def saveTFE(feedback: TripFeedbackEvent) = kleisli(_.save(feedback))
def saveLFE(feedback: LibraryFeedbackEvent) = kleisli(_.save(feedback))
def findByUser(userId: Id) = kleisli(_.findByUser(userId))
...
}
我按照书上的设计Functional and Reactive Domain Modeling
并且对于某些服务方法,它只将工作委托给存储层。有没有办法减少这个样板:
trait FeedbackServiceImpl extends FeedbackService {
override def saveTFE(feedback: TripFeedbackEvent) =
Kleisli[Future, Context, Either[String, Id]] { ctx => ctx.feedbackRepo.save(feedback) }
override def saveLFE(feedback: LibraryFeedbackEvent) =
Kleisli[Future, Context, Either[String, Id]] { ctx => ctx.feedbackRepo.save(feedback) }
override def findByUser(userId: Id) =
Kleisli[Future, Context, Seq[FeedbackEvent]] { ctx => ctx.feedbackRepo.findByUser(userId) }
override def all =
Kleisli[Future, Context, Seq[FeedbackEvent]] { ctx => ctx.feedbackRepo.all }
override def findByTip(tipId: Id) =
Kleisli[Future, Context, Seq[FeedbackEvent]] { ctx => ctx.feedbackRepo.findByTip(tipId) }
}
您能否只定义一个执行所有样板文件的函数?类似于:
def repo2Kleisli[T](f: Repo => Future[T]): Kleisli[Future, Context, T]
您甚至可以将其隐式化并将您的代码简化为:
override def saveTFE(feedback: TripFeedbackEvent) = (repo: Repo) => repo.save(feedback)
我们可以创建一个 组合器 :
private def kleisli[M[_], A](f: FeedbackRepository => M[A]) =
Kleisli.kleisli(f).local[Context](_.feedbackRepo)
因此我们得到了两件事:
- 通过帮助类型推断机制避免声明类型
- 避免使用
local
调用
ctx.feedbackRepo
所以我们可以使用:
trait Feedbacks {
def saveTFE(feedback: TripFeedbackEvent) = kleisli(_.save(feedback))
def saveLFE(feedback: LibraryFeedbackEvent) = kleisli(_.save(feedback))
def findByUser(userId: Id) = kleisli(_.findByUser(userId))
...
}