我正在尝试在Scala中编写来自Data Types ala Carte的foldTerm
函数。这是我到目前为止所得到的
def foldTerm[F[+_], A, B](e: Free[F, A], pure: A ⇒ B, imp: F[B] ⇒ B)(implicit F: Functor[F]): B =
e.resume match {
case Right(a) ⇒ pure(a)
case Left(x) ⇒ imp(F.map(x)(foldTerm(_, pure, imp)))
}
这样可行,但由于Scala无法正确优化尾递归,因此会导致SOE。我试图用Trampoline
修复它,但到目前为止还没有运气。我觉得我应该能够使用Free
上现有的方法做到这一点,但我的所有尝试都以挫败感结束了。
我错过了什么?
答案 0 :(得分:2)
Scala可以正确地消除尾递归调用。但是你的方法不是尾递归的。您可以使用@annotaion.tailrec
注释进行检查。
@annotation.tailrec
def foldTerm[F[+_], A, B](e: Free[F, A], pure: A ⇒ B, imp: F[B] ⇒ B)(implicit F: Functor[F]): B =
e.resume match {
case Right(a) ⇒ pure(a)
case Left(x) ⇒ imp(F.map(x)(foldTerm(_, pure, imp)))
}
<console>:19: error: could not optimize @tailrec annotated method foldTerm: it contains a recursive call not in tail position
case Left(x) ⇒ imp(F.map(x)(foldTerm(_, pure, imp)))
此处的最后一次通话是imp
,而不是foldTerm
。
答案 1 :(得分:2)
事实证明这不是我的问题。我在一个大型列表中使用ListT.fromList
,这就是堆栈的内容。切换到使用StreamT
解决了问题。