如何将`scalaz.FreeT`运行到非堆栈安全的monad中?

时间:2016-03-15 14:57:07

标签: scala scalaz

我试图绕着自由的monad(和变形金刚)。我已经能够使用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)

所以,第一个也是不那么重要的问题是,我是否必须在oder中进行提升才能将免费monad运行到其他任意monad中?似乎有些过分......

主要课程:.runM要求ResultMonad提供一个BindRec实例,证明可以在ResultMonad的常量堆栈空间中绑定。我希望有一个使用scala.concurrent.Future运行我的免费monad的解释器 - 这不是堆栈安全的。有没有办法做到这一点?我知道我放弃了某种保证,但作为开发人员,我可以确信Future.flatMap堆栈不会足够深,导致任何麻烦(我们使用普通{{1到处都没有免费的monad,它工作正常)

我使用的是Scalaz 7.2.1,据我所知,这是最新版本。

旁注:我知道Futures存在,我仍然想知道如何将免费monad解释为scalaz.concurrent.Task

1 个答案:

答案 0 :(得分:1)

回答您的第一个问题:如果您只有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上执行的话,这甚至可能是堆栈安全的,但我对它不够熟悉)