Yan*_*san 4 functional-programming scala scalaz kleisli
我遵循了优秀书籍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)
}
}
Run Code Online (Sandbox Code Playgroud)
由于类型不对齐,我收到以下编译错误
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
^
Run Code Online (Sandbox Code Playgroud)
解决这个问题的最佳方法是什么,创建一个
trait Context {
def userRepo
def projectRepo
}
Run Code Online (Sandbox Code Playgroud)
和污染UserService和ProjectService它?
您需要想出某种方法将输入类型合并为一个类型。这样做将是一个方法的继承-你会拥有一种UserRepo with ProjectRepo是两者的子类UserRepo和ProjectRepo。另一种方法是组合,你有一个 tuple (UserRepo, ProjectRepo)。
在这两种情况下,您通常会使用local“扩展”每个箭头的输入类型,以便您可以在for-comprehension 中组合它们:
for {
user <- findByUserId.local[(UserRepo, ProjectRepo)](_._1)
project <- findProjectById.local[(UserRepo, ProjectRepo)](_._2)
} yield (user, project)
Run Code Online (Sandbox Code Playgroud)
这里的(UserRepo, ProjectRepo)类型参数参数指定了新的输入类型,而值参数(例如_._1)指定了如何从新的输入类型获得原始箭头的输入类型。