I'm trying to stack monad transfromers of scalaz
in a haskell way:
statyReader :: (MonadReader Int m, MonadState Int m) => m Int
scala:
def statyReader[F[_]](implicit r: MonadReader[F, Int], s: MonadState[F, Int]): F[Int] = for {
counter <- s.get
secret <- r.ask
_ <- s.put(counter + secret)
} yield counter
It compiles with 1 implicit passed, but not with 2:
Error:(13, 18) value flatMap is not a member of type parameter F[Int]
counter <- s.get
^
Error:(14, 18) value flatMap is not a member of type parameter F[Int]
secret <- r.ask
^
Error:(15, 21) value map is not a member of type parameter F[Unit]
_ <- s.put(counter + secret)
^
Why is this happening? My guess is that compiler is now confused which "monadic instance of F[_]
" it should pick(both MonadReader and MonadState extend Monad[F[_]
). Is this a right guess?
How to overcome this?
This is not really an answer, but maybe helps a bit.
I think you're right; it seems like the compiler can't unify the F[_]
types of both parameters (I guess since it is a higher-kinded type with multiple possible instances and not a concrete type instance) to a monad type. Compilation works with separate parameter lists since type unification only happens within a parameter list. It can be further illustrated like this:
def statyReader[F[_]](implicit r: MonadReader[F, Int], s: MonadState[F, Int]): F[Int] =
statyReader2(r, s)
def statyReader2[F[_]:Monad](r: MonadReader[F, Int], s: MonadState[F, Int]): F[Int] =
for {
counter <- s.get
secret <- r.ask
_ <- s.put(counter + secret)
} yield counter
Error: ambiguous implicit values: both
value s of type scalaz.MonadState[F,Int] and
value r of type scalaz.MonadReader[F,Int]
match expected type scalaz.Monad[F]
Obviously, as a workaround you could use two parameter lists to choose which monad you want to use:
def statyReader[F[_]](implicit r: MonadReader[F, Int], s: MonadState[F, Int]): F[Int] =
statyReader2(r)(s)
def statyReader2[F[_]](r: MonadReader[F, Int])(implicit s: MonadState[F, Int]): F[Int] =
for {
counter <- s.get
secret <- r.ask
_ <- s.put(counter + secret)
} yield counter
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With