4

我遵循优秀书籍Reactive Domain Modeling的设计,我需要混合Kleisli不同的类型:

object CombinedKleisli {
  type User = String
  type Project = String

  trait UserRepo
  trait ProjectRepo
  trait UserService {
    def findByUserId : Kleisli[Future, UserRepo, User]
  }
  trait ProjectService {
    def findProjectById : Kleisli[Future, ProjectRepo, Project]
  }
  trait ComposedService extends UserService with ProjectService {
    for {
      user <- findByUserId
      project <- findProjectById
    } yield (user, project)
  }

}

由于类型不对齐,我收到以下编译错误

Error:(28, 15) type mismatch;
 found   : scalaz.Kleisli[scala.concurrent.Future,domain.service.ServiceTest.ProjectRepo,(domain.service.ServiceTest.User, domain.service.ServiceTest.Project)]
    (which expands to)  scalaz.Kleisli[scala.concurrent.Future,domain.service.ServiceTest.ProjectRepo,(String, String)]
 required: scalaz.Kleisli[scala.concurrent.Future,domain.service.ServiceTest.UserRepo,?]
      project <- findProjectById
              ^

解决这个问题的最佳方法是什么,创建一个

trait Context {
  def userRepo
  def projectRepo
}

和污染UserServiceProjectService它?

4

1 回答 1

5

您需要想出一些方法将输入类型组合成单一类型。做到这一点的一种方法是继承——你将拥有一个类型UserRepo with ProjectRepo,它是 and 的子UserRepoProjectRepo。另一种方法是组合,你有一个 tuple (UserRepo, ProjectRepo)

在这两种情况下,您通常会使用local“扩展”每个箭头的输入类型,以便您可以在for-comprehension 中组合它们:

for {
  user <- findByUserId.local[(UserRepo, ProjectRepo)](_._1)
  project <- findProjectById.local[(UserRepo, ProjectRepo)](_._2)
} yield (user, project)

在这里,(UserRepo, ProjectRepo)type 参数参数指定新的输入类型,而 value 参数(例如_._1)指定如何从新输入类型获取原始箭头的输入类型。

于 2016-03-17T16:04:19.227 回答