我有这个迭代函数,它计算列表中布尔值的数量。
def countBoolIter[A](test: A=>Boolean, a: List[A]) = {
var count = 0
for(elem <- a){
if(test(elem)) count += 1
}
count
}
传入的第一个参数是isBool
函数:
def isBool(i: Any) = i match {
case _: Boolean => true
case _ => false
}
调用函数如下所示:
countBoolIter(isBool, List(1, true, 3, true, false, "hi"))
// Output: 3
现在,我尝试将其转换为尾递归函数,如下所示:
def countBoolRec[A](test: A=>Boolean, a: List[A], acc: Int = 0): Int = a match {
case Nil => acc
case h :: t if(test(h)) => countBoolRec(test, a, acc+1)
case h :: t => countBoolRec(test, a, acc)
}
但是,我收到运行时错误,因为该函数没有返回任何内容;没有错误被抛出。我认为它陷入无限循环,这就是为什么没有返回的原因。
问题:我应该如何解决我尝试的递归实施?
答案 0 :(得分:1)
函数countBoolRec中存在错误:
@tailrec
def countBoolRec[A](test: A=>Boolean, a: List[A], acc: Int = 0): Int = a match {
case Nil => acc
case h :: t if(test(h)) => countBoolRec(test, t, acc+1)
case h :: t => countBoolRec(test, t, acc)
}
在递归调用中,使用t作为参数,不再使用a。如果没有,基本上,你处于无限循环中。
另外,最好使用@tailrec注释来确保实现是“尾递归”。
答案 1 :(得分:1)
您反复使用与输入相同的列表进行递归。
考虑a.head通过测试的情况:
countBoolRec(test,a,0) countBoolRec(test,a,1) countBoolRec(test,a,2) ......等等
@scala.annotation.tailrec // Not that your original code wasn't tail-recursive, but it's a generally good practice to mark code that isn't tail recursive with this annotation
def countBoolRec[A](test: A=>Boolean, a: List[A], acc: Int = 0): Int = a match {
case Nil => acc
case h :: t if (test(h)) => countBoolRec(test, t, acc + 1)
case h :: t => countBoolRec(test, t, acc)
}
虽然你也可以写:
(0 /: a) { (acc, v) => acc + (if (test(v)) 1 else 0) }