Как совместить Клейсли [M, A, C] и Клейсли [M, B, C]
Я следую за дизайном превосходной книги 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
}
и загрязнять UserService
а также ProjectService
с этим?
1 ответ
Вам нужно будет придумать способ объединить типы ввода в один тип. Одним из способов сделать это было бы наследование - у вас был бы тип UserRepo with ProjectRepo
это подкласс обоих UserRepo
а также ProjectRepo
, Другим способом будет состав, где у вас есть кортеж (UserRepo, ProjectRepo)
,
В обоих случаях вы обычно используете local
"расширить" типы ввода каждой стрелки, чтобы вы могли составить их в for
-comprehension:
for {
user <- findByUserId.local[(UserRepo, ProjectRepo)](_._1)
project <- findProjectById.local[(UserRepo, ProjectRepo)](_._2)
} yield (user, project)
Здесь (UserRepo, ProjectRepo)
Параметр типа аргумент определяет новый тип ввода и значение аргумента (например, _._1
) определяет, как получить исходный тип ввода стрелки из нового типа ввода.