I am trying to implement a generic DAO, which can be extended for MongoDB, SQL, etc. I define the interface
methods with a generic type definition, Method[+T]. This type definition is declared by each concrete DAO for
example MongoDB may define it as follows:
type Method[+T] = Option[T]
For my case I have a concrete implementation that requires:
type Method[+T] = EitherT[C, A, T] where C is another monad and A is some other non-important type.
I use scalaz Either transform (EitherT) because I need to be able to compose methods and therefore unwrap
nested monads with for-comprehensions. Without the usage of EitherT I cannot handle situations like
Option[Either[Int, Int]] which correspond to EitherT[Option, Int, Int]. The following code conveys the shortcomings:
Without EitherT:
case class Reader[+A](f: A => Either[Int, Int]) {
def apply(v: A): Either[Int, Int] = f(v)
}
def foo() = Reader( a:Int => Right( a+1 ) )
val bar: Either[Int, Int] = for {
b <- foo().apply(9).right
} yield b
With EitherT:
def foo() = EitherT( Reader( a:Int => Right( a+1 ) ) )
val bar: EitherT[Reader, Int, Int] = for {
b <- foo()
} yield b
b.run(9)
As you can see the second implementation is much cleaner, however it causes compile time issues.
The problem with this approach is that +T is covariant and is supplied to a covariant position in EitherT[ F[ _ ], A, B ].
Any assistance is greatly appreciated. Thank you!