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

时间:2019-03-19 07:48:37

标签: scala scala-cats

我正在使用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

2 个答案:

答案 0 :(得分: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)

答案 1 :(得分:0)

可以使用cats-par库,也可以根据建议的here添加辅助Models\MyData.edmx that contains Context.tt 类型的类。

然后Parallel1仅需要一个类型参数:

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