如何调用使用MTL和Parallel的函数?

问题描述 投票:1回答:2

我正在使用Parallel类型类来收集所有验证错误:

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)

getUser函数有两个类型参数:

  • M是我的monad变压器堆栈,
  • F是一些应用程序,它与M双重但允许并行执行。

然后我想用下面的monad变换器堆栈来调用它:

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

我需要指定M类型参数来告诉编译器我正在使用哪个堆栈。但是我必须指定F参数:

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

这看起来很难看。有没有办法让编译器推断F

完整代码在这里:https://gist.github.com/vkorenev/21bdd7d57e81a0752972f4bb3f45398a

scala scala-cats
2个回答
2
投票

尝试“部分申请”

  def getUser[M[_]](implicit E: MonadError[M, Errors],
                    R: ApplicativeAsk[M, Params],
                    W: FunctorTell[M, List[String]]
                   ) = new GetUserHlp[M]

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

  getUser[Stack].apply.value.run.run(params)

或者创建一个类型类

  trait GetUser[M[_]] {
    def apply(): M[User]
  }

  object GetUser {
    implicit def default[M[_], F[_]](implicit E: MonadError[M, Errors],
                                     R: ApplicativeAsk[M, Params],
                                     W: FunctorTell[M, List[String]],
                                     P: Parallel[M, F]
                                    ): GetUser[M] = new GetUser[M] {
      override def apply(): M[User] = (getNonEmptyStr("name"), getInt("age"), getNonEmptyStr("address"))
        .parMapN(User)
    }
  }

  def getUser[M[_]](implicit gu: GetUser[M]): M[User] = gu()

  getUser[Stack].value.run.run(params)

0
投票

可以使用cats-par库或添加辅助Parallel1类型类建议here

那么getUser只需要一个类型参数:

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

希望其中一个修复程序将添加到cats

© www.soinside.com 2019 - 2024. All rights reserved.