如何运行'scalaz.FreeT' 变成非堆栈安全的 monad



我试图围绕免费的monads(和变压器)来包装我的头。我已经能够使用 scalaz.FreeT 和一个解释器构建我自己的自由 monad,该解释器首先天真地提升到目标 monad 中,然后运行自由 monad,将其运行到看似任意的 monad,如下所示:

import scalaz._
import Scalaz._
type MyCoolMonad[A] = FreeT[SomeFunctor, Id, A]
type ResultMonad[A] = ??? // for example Id[A]
def id2monadNT[R[_]: Monad]: (id ~> R) = { 
  override def apply[A](fa: A) = fa.point[R]
} // for hoisting
val myInterpreter = new (SomeFunctor ~> ResultMonad) {
  override def apply[A](fa: SomeFuntor[A]) = {...} // the meat is here
}
def runCoolMonad[A](m: MyCoolMonad[A]) = 
  m.hoistN(id2monadNT[R]).runM(myInterpreter.apply)

所以,第一个也是不太重要的问题是,我是否必须进行吊装才能将自由的 monad 运行到其他任意的 monad 中?似乎有些过分了...

主菜:.runM 要求ResultMonad提供一个BindRec实例,证明可以在恒定堆栈空间中绑定ResultMonad。因此,我希望有一个解释器使用scala.concurrent.Future运行我的免费monad-这不是堆栈安全的。有什么办法可以做到这一点吗?我知道我放弃了一定的保证,但作为开发人员,我可以有信心Future.flatMap堆栈不会足够深以造成任何麻烦(我们使用的是没有免费 monads 的普通Futures,它工作正常)

我正在使用 Scalaz 7.2.1,据我所知,这是最新的。

旁注:我知道scalaz.concurrent.Task的存在,我仍然想知道如何将自由monad解释为scala.concurrent.Future

回答你的第一个问题:如果你只有FreeT[SomeFunctor, Id, A],就相当于Free[SomeFunctor, A]。然后给定SomeFunctor ~> Future,就可以将Free[SomeFunctor, A]解释为Future[A]。即无需FreeT和吊装。此外,Free允许您解释为任何 monad。

FreeTscalaz的最新补充。虽然Free最初被设计为解释任何monad,并且堆栈安全版本的操作是后来才添加的,但从一开始就FreeT仅支持堆栈安全monad。

如果您仍想将FreeTscala.concurrent.Future 一起使用,只需提供一个BindRec实例。

implicit def futureBindRec: BindRec[Future] = new BindRec[Future] {
  def tailrecM[A, B](f: A => Future[A / B])(a: A): Future[B] =
    f(a) flatMap {
      case -/(a1) => tailrecM(f)(a1)
      case /-(b) => Future(b)
    }
  def map...
  def bind...
}

这甚至可能是堆栈安全的,如果Future#flatMap(f)从不急切地调用f(也许它在完成的Future上确实如此,但我对它不够熟悉,无法告诉)。

最新更新