如何 运行 `scalaz.FreeT` 进入非堆栈安全的 monad?
How to run `scalaz.FreeT` into non-stack-safe monad?
我正在努力思考免费的 monad(和转换器)。我已经能够使用 scalaz.FreeT
和一个解释器构建我自己的免费 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
实例,证明可以在常量堆栈[=35=中绑定ResultMonad
].我希望有一个解释器 运行s 我的免费 monad 结果使用 scala.concurrent.Future
- 这不是堆栈安全的。有什么办法吗?我知道我放弃了某种保证,但作为开发者,我可以相信 Future.flatMap
堆栈不会深到足以造成任何麻烦(我们使用的是普通的 Futures
而没有免费的monads 无处不在,它工作正常)
我正在使用 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]
。 IE。不需要 FreeT
和提升。此外,Free
允许您解释为任何 monad。
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(和转换器)。我已经能够使用 scalaz.FreeT
和一个解释器构建我自己的免费 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
实例,证明可以在常量堆栈[=35=中绑定ResultMonad
].我希望有一个解释器 运行s 我的免费 monad 结果使用 scala.concurrent.Future
- 这不是堆栈安全的。有什么办法吗?我知道我放弃了某种保证,但作为开发者,我可以相信 Future.flatMap
堆栈不会深到足以造成任何麻烦(我们使用的是普通的 Futures
而没有免费的monads 无处不在,它工作正常)
我正在使用 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]
。 IE。不需要 FreeT
和提升。此外,Free
允许您解释为任何 monad。
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
上调用,但我对它不够熟悉告诉)。