scalaz蹦床和IO

scalaz蹦床和IO,scala,scalaz,scalaz7,Scala,Scalaz,Scalaz7,这个问题与另一个问题相关,但简化为更简单的情况: 我假设以下情况: import scalaz._, Scalaz._ import Free._, effect._ 我有以下发电机: val fromOneIO: () => IO[Int] = { var i = 0; () => { i += 1; IO(i) } } val fromOne: () => Int = { var i = 0; () => { i += 1; i } } 以及以下非尾部递

这个问题与另一个问题相关,但简化为更简单的情况:

我假设以下情况:

import scalaz._, Scalaz._
import Free._, effect._
我有以下发电机:

val fromOneIO: () => IO[Int] = {
  var i = 0; () => { i += 1; IO(i) }
} 
val fromOne: () => Int = {
  var i = 0; () => { i += 1; i }
}
以及以下非尾部递归定义:

def rec(i: Int): Int = {
  if (i == 0) {
    fromOne()
  } else {
    rec(i - 1) + fromOne()
  }
}
def rec1(i: Int): Trampoline[Int] = {
  if (i == 0) {
    Return(fromOne())
  } else {
    suspend {
      for {
        a <- rec1(i - 1)
        b <- Return(fromOne()): Trampoline[Int]
      } yield a + b
    }
  }
}
def recio(i: Int): Trampoline[IO[Int]] = {
  if (i == 0) {
    Return(fromOneIO())
  } else {
    suspend {
      for {
        ioa <- recio(i - 1)
        iob <- Return(fromOneIO()): Trampoline[IO[Int]]
      } yield {
        for (a <- ioa; b <- iob) yield a + b
      }
    }
  }
}
如何使IO地图/平面地图也能蹦床?我似乎在第二个堆栈中创建了其他嵌套堆栈以供理解。我是否需要编写一个
蹦床
,它将使用
unsafePerformIO
,并将提取的io值重新写入一个挂起状态?

因此,不管它值多少钱,它已经是这样了。除了folone的建议外,我还可以通过将第二个更改为如下方式来避免溢出:

val s = for (a <- ioa; b <- iob) yield a + b
val s1 = s.unsafePerformIO()
IO(s1)
IO(for (a <- ioa; b <- iob) yield a + b).flatMap(identity)

因此,尽管这不是一个非常令人满意的答案,但它似乎在可能的情况下使用应用程序,或者在另一个
IO
中包装并展平将是清理堆栈的解决办法。

对于这个特定的示例,
IO[a:Monoid]
的一个
Monoid
实例似乎起到了作用。也就是说,只需将
yield
语句更改为
ioa++iob
。不过,我没有什么可以推荐的。实际上,问题似乎出在
IO
Monad
实例中。如果您使用它的
Applicative
实例,它似乎工作得很好
yield(ioa |@| iob){uu+}
您想要的是
IO
本身被践踏,而不是构建一个庞大的嵌套
IO
操作链的函数。您的代码允许您构建一个
IO
操作,而不会使堆栈溢出,但是,当您运行
IO
操作时,构建它的方式将导致堆栈溢出。@folone,有趣的是applicative不会溢出。我试图找到它,但找不到
F.lift2
的实现。我希望scalaz7仍然有从Harrah的x光片构建的交叉引用源代码。@MyseriousDan,我仍然需要处理
recio
不是尾部递归的事实。所以我需要两层蹦床。所以我的问题是如何实现IO的第二个目标。
IO(for (a <- ioa; b <- iob) yield a + b).flatMap(identity)
val s = for (a <- ioa; b <- iob) yield a + b
IO(s.unsafePerformIO())