如何将'scalaz.FreeT'运行到非堆栈安全monad中?
我正试着把我的头绕在免费的单子(和变形金刚)上。我已经能够使用如何将'scalaz.FreeT'运行到非堆栈安全monad中?,scala,scalaz,Scala,Scalaz,我正试着把我的头绕在免费的单子(和变形金刚)上。我已经能够使用scalaz.FreeT和一个解释器构建我自己的免费monad,该解释器将它运行到一个看似任意的monad中,首先天真地提升到目标monad中,然后运行免费monad,如下所示: import scalaz._ import Scalaz._ type MyCoolMonad[A] = FreeT[SomeFunctor, Id, A] type ResultMonad[A] = ??? // for example Id[A] d
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)
因此,第一个也是不太重要的问题是,我是否必须提升,以便将自由单子运行到其他任意单子中?似乎有点过分了
主要过程是:.runM
需要ResultMonad
提供一个BindRec
实例,证明可以在恒定的堆栈空间中绑定ResultMonad
。我希望有一个解释器运行我的免费monad,结果是使用scala.concurrent.Future
,这不是堆栈安全的。有办法吗?我知道我放弃了某种保证,但作为开发人员,我有信心Future.flatMap
堆栈不会太深而引起任何麻烦(我们使用的是纯Futures
,到处都没有免费的monad,而且工作正常)
我正在使用Scalaz 7.2.1,据我所知,它是最新的
旁注:我知道存在
scalaz.concurrent.Task
,我仍然想知道如何将free monad解释为scala.concurrent.Future
来回答你的第一个问题:如果你只有FreeT[SomeFunctor,Id,A]
,它相当于free[SomeFunctor,A]
。然后给定SomeFunctor~>Future
,您可以将Free[SomeFunctor,A]
解释为Future[A]
。也就是说,无需使用FreeT
和吊装。另外,Free
允许您对任何单子进行解释
FreeT
是对scalaz
的最新添加。虽然Free
最初设计用于解释任何monad,而堆栈安全版本的操作只是后来添加的,FreeT
从一开始就只支持堆栈安全monad
如果您仍然希望将FreeT
与scala.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
上可能会这样做,但我对它还不太熟悉,所以我宁愿构建monad转换器,而不是简单的monad,因为它具有可组合性。关于提供BindRec[Future]
实例的观点很好——我只是盲目地认为这是不可能的,我将检查这是否有效。我最初的问题已经解决了,但是对于如何在真正非堆栈安全的monad中解释FreeT
,您还有其他见解吗?BindRec
的上述实现几乎可以一字不差地适用于任何monad。它只是有可能在某些情况下溢出堆栈。另一种迂回的方法是将FreeT[S,M,A]
提升到FreeT[S,Free[M,A]
,将其解释为Free[M,A]
(这是堆栈安全的),然后将其解释为非堆栈安全的monadM
。当然FreeT
可以通过解释为任何monad的方法进行扩展。我不相信它会非常有用。