这是一个scala代码示例-
def foo(n : Int, ls : List[Int]) : Int =
ls match {
case Nil => n
case hd :: tl => hd*foo(n-1,tl)
}
如果我通过foo(7,List(1,2,-2,2))
,则会得到-24,但我不明白这是如何工作的,有人能帮助我理解递归在这里是如何工作吗?
由于我不完全确定你在问什么,这可能过于详细了。
在match
:中
case Nil
将匹配(并且仅匹配(一个空列表case hd :: tl
将破坏列表(如何/为什么这样做的确切机制超出了这个答案的范围(,其中值hd
是列表的第一个元素,值tl
是包含第一个元素之后的每个元素的列表
因此,继续使用评估的替代模型,我们最终得出:
foo(7, List(1, 2, -2, 2))
:列表(ls
(不为空,因此第二个match子句匹配,结果为1 * foo(6, List(2, -2, 2))
:列表是非空的,所以第二个match子句匹配,结果是(由于乘法是关联的,所以简化后(1 * 2 * foo(5, List(-2, 2))
:列表不为空,因此第二个match子句匹配,结果为1 * 2 * -2 * foo(4, List(2))
:列表不为空,因此第二个match子句匹配,结果为1 * 2 * -2 * 2 * foo(3, Nil)
:列表为空,因此第一个match子句匹配,结果为1 * 2 * -2 * 2 * 3
:乘出去是-24
对于一些人来说,这个函数的逻辑最好表示为
def foo(n: Int, ls: List[Int]): Int =
if (ls.isEmpty) n
else ls.head * foo(n - 1, ls.tail)
经过一点代数运算,它也可以表示为
(n - ls.length) * ls.product
尽管对于将比递归实现慢的List
(因为.length
和.product
将各自完全遍历列表(。
我在您的原始答案中添加了println,它打印执行堆栈跟踪,就像Levi在他的答案中解释的那样。这个技巧应该有助于其他递归示例来理解执行流:
def printMul(xs: List[Int]) = if (xs.nonEmpty) xs.mkString(" * ") + " * " else ""
def foo(n: Int, ls: List[Int], prev: List[Int] = Nil): Int =
ls match {
case Nil =>
println(s"${printMul(prev)}$n")
n
case hd :: tl =>
println(s"${printMul(prev)}$hd * foo(${n - 1}, $tl)")
hd * foo(n - 1, tl, prev :+ hd)
}
// ====== Output ======
/*
1 * foo(6, List(2, -2, 2))
1 * 2 * foo(5, List(-2, 2))
1 * 2 * -2 * foo(4, List(2))
1 * 2 * -2 * 2 * foo(3, List())
1 * 2 * -2 * 2 * 3
*/
ls
传递的列表为Nil
(空(时,foo
终止。
每次调用foo
时,ls
都通过模式匹配提取其头部(hd
(和尾部(tl
(。头与下一个仅取列表尾部的foo
调用相乘(以及将n
值减去1。
当评估foo(7,List(1,2,-2,2))
时,下一步是1 * foo(6, List(2, -2, 2))
,依此类推…