在Scala中的'Data types ala Carte'中编写foldTerm

时间:2012-07-13 01:48:15

标签: scala scalaz

我正在尝试在Scala中编写来自Data Types ala CartefoldTerm函数。这是我到目前为止所得到的

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上现有的方法做到这一点,但我的所有尝试都以挫败感结束了。

我错过了什么?

2 个答案:

答案 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解决了问题。