如何将Free monads转换为Free appativeatives

时间:2019-07-18 18:21:38

标签: scala monads scalaz scala-cats

我正在使用cats库,并且想要将Free Monad转换为Free Appativeative。

我们在Free monads中有很多代码。。但是,现在应用程序的某些部分必须并行运行。可以选择使用Tagless或Frees.io而不是Free。但这将是一个巨大的改变...

这是一个示例DSL:

sealed trait DSLAction[A]

case class GetCustomer(request: Boolean) extends DSLAction[String]

case class GetSize(request: Boolean) extends DSLAction[Int]

val f1: Free[DSLAction, String] = liftF(GetCustomer(true))
val f2: Free[DSLAction, Int] = liftF(GetSize(true))
val f3: Free[DSLAction, Int] = liftF(GetSize(false))

  val interpreter: DSLAction ~> Id = {
    λ[DSLAction ~> Id] {
      case GetCustomer(_: Boolean) => {
        "hello"
      }
      case GetSize(_: Boolean) => {
        123
      }
    }
  }

Cats库提供了一种使用.monad()将FreeApplicative转换为Free monad的方法

但是,我想将Free转换为FreeApplicative以便将其用于理解

我想定义一个方法toApplicative()完成工作...

type FEF[A] = FreeApplicative[DSLAction, A]

val f1AP: FEF[String] = toApplicative(f1)
val f2AP: FEF[Int] = toApplicative(f2)


val prog = for {
    a <- (f1AP, f2AP).mapN { case (l, r) => l + r }.monad
    b <- f3
  } yield {
    (a, b)
  }


  prog.foldMap(interpreter)

我确实尝试实现一些东西。但是不确定如何定义flatMap和tailRec方法。

或者可能有另一种方式

  implicit val myConvertor = new Monad[FEF] {

    override def pure[A](x: A): FEF[A] = FreeApplicative.pure[DSLAction,A](x)

    override def flatMap[A, B](fa: FEF[A])(f: A => FEF[B]): FEF[B] = ???

    override def tailRecM[A, B](a: A)(f: A => FEF[Either[A, B]]): FEF[B] = ???
  }


  final def toApplicative[F, A](free: Free[DSLAction, A]) =
    free.foldMap[FreeApplicative[DSLAction, ?]] {
      λ[FunctionK[DSLAction, FEF]](fa => FreeApplicative.lift(fa))
    }

谢谢

1 个答案:

答案 0 :(得分:0)

尝试

implicit val myConvertor = new Monad[FEF] {
  override def pure[A](x: A): FEF[A] = FreeApplicative.pure[DSLAction,A](x)
  override def flatMap[A, B](fa: FEF[A])(f: A => FEF[B]): FEF[B] = toApplicative(Monad[Free[DSLAction, ?]].flatMap(fa.monad)(a => f(a).monad))
  override def tailRecM[A, B](a: A)(f: A => FEF[Either[A, B]]): FEF[B] = toApplicative(Monad[Free[DSLAction, ?]].tailRecM(a)(a => f(a).monad))
}

实际上toApplicative不起作用,因为它需要Monad[FreeApplicative[DSLAction,?]]并且这种实例不存在,FreeApplicative[DSLAction,?]Applicative,而不是Monad(相反,FreeApplicative#monad起作用是因为存在Monad[Free[DSLAction,?]])。

https://typelevel.org/cats/datatypes/freeapplicative.html#differences-from-free

  

到目前为止,我们一直在做的一切与   Free-我们建立了一个代数并对其进行了解释。但是,有   FreeApplicative可以做到Free无法做到的某些事情。

所以我想有从FreeApplicative[DSLAction,?]Free[DSLAction,?]的转换,但是没有从Free[DSLAction,?]FreeApplicative[DSLAction,?]的转换。通常,您不能从功能较少的事情(FreeApplicative仅可以连续执行)中获得更多可以做的事情(Free可以并行执行和连续执行)。

FreeMonad,因此它是Applicative,但是此Applicative实例与Applicative实例是FreeApplicative实例不同

@bogdanVakulenko在reddit的链接中的引言

  

将单子变成应用中的应用程序确实是不可能的   一般情况,因为许多应用程序(例如Const[M: Monoid])不   形成单子。如果您的单子保留了两者之间的区别   应用操作和单子操作,那么它就不再免费