How to combine Kleisli [M, A, C] and Kleisli [M, B, C]

I follow the design of the excellent Reactive Domain Modeling book, and I need to mix Kleisliwith various types:

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)
  }

}

And since the types are not aligned, I get the following compilation error

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
              ^

What is the best way to fix this by creating

trait Context {
  def userRepo
  def projectRepo
}

and contaminate UserService, and ProjectServiceto him?

+4
source share
1 answer

You will need to somehow combine the input types into one type. One way to do this is through inheritance - you will have a type UserRepo with ProjectRepothat is a subclass of both UserRepo, and so on ProjectRepo. Another way is composition where you have a tuple (UserRepo, ProjectRepo).

local "" , for -:

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

(UserRepo, ProjectRepo) , (, _._1) , .

+4

All Articles