이 질문은 훨씬 간단 경우이 다른 question 관련이 있지만, 감소scalaz 트램폴린 및 IO
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
}
}
}
}
결과는 다음과 같습니다
rec(100) // overflows for arg 10000
rec1(10000).run // works
recio(10000).run.unsafePerformIO() //overflows
어떻게 IO지도 /뿐만 아니라 trampolined 수 flatMap하게 관리 할 수? 그것은 다른 중첩 된 스택 내면 이해를 위해 만든 것 같습니다. unsafePerformIO
을 사용할 TrampolineT
을 작성하고 추출 된 io 값을 일시 중단에 다시 랩핑해야합니까?
이 특정 예에서'IO [A : Monoid]'에 대한'Monoid' 인스턴스가 작동하는 것 같습니다. 즉, 'yield'문을'ioa | + | '로 변경하면됩니다. iob'. 나는 더 넓은 그림을 위해 추천 할 아무것도 가지지 않고있다. – folone
사실, 문제는'IO'에 대한'Monad' 인스턴스에있는 것 같습니다. 'Applicative' 인스턴스를 사용하면 잘 작동하는 것 같습니다. 'yield (ioa | @ | iob) {_ + _}' – folone
'IO' 자체가 트램 폴린되기를 원한다. 당신의 코드는 스택 오버 플로우없이'IO' 액션을 구현할 수있게 해줍니다.하지만 당신이 그것을 빌드하는 방법은'IO' 액션을 실행할 때 스택 오버플로를 일으킬 것입니다. –