Search code examples
scalascala-cats

How to call a function which uses MTL and Parallel?


I am using Parallel type class in order to collect all validation errors:

def getNonEmptyStr[M[_]](key: String)(
    implicit
    E: MonadError[M, Errors],
    A: ApplicativeAsk[M, Params],
    W: FunctorTell[M, List[String]]
): M[String] = ???

def getInt[M[_]](key: String)(
    implicit
    E: MonadError[M, Errors],
    A: ApplicativeAsk[M, Params],
    W: FunctorTell[M, List[String]]
): M[Int] = ???

def getUser[M[_], F[_]](
    implicit E: MonadError[M, Errors],
    R: ApplicativeAsk[M, Params],
    W: FunctorTell[M, List[String]],
    P: Parallel[M, F]
): M[User] = 
    (getNonEmptyStr("name"), getInt("age"), getNonEmptyStr("address"))
        .parMapN(User)

The getUser function has two type parameters:

  • M is my monad transformer stack,
  • F is some applicative which is dual to M but allows parallel execution.

Then I want to call it with the following monad transformer stack:

type Stack[A] = EitherT[WriterT[Reader[Params, ?], List[String], ?], Errors, A]

I need to specify the M type parameter to tell the compiler which stack I am using. But then I have to specify the F parameter as well:

getUser[Stack, Nested[WriterT[Reader[Params, ?], List[String], ?], Validated[Errors, ?], ?]].value.run.run(params)

This looks pretty ugly. Is there any way to let compiler infer F?

Full code is here: https://gist.github.com/vkorenev/21bdd7d57e81a0752972f4bb3f45398a


Solution

  • It is possible to either use cats-par library or to add an auxiliary Parallel1 type class as suggested here.

    Then getUser will need only one type parameter:

    def getUser[M[_]](
        implicit
        E: MonadError[M, Errors],
        R: ApplicativeAsk[M, Params],
        W: FunctorTell[M, List[String]],
        P: Parallel1[M]
    ): M[User] = {
      import P._
      (getNonEmptyStr("name"), getInt("age"), getNonEmptyStr("address")).parMapN(User)
    }
    

    Hopefully, one of the fixes will be added to cats.