Scala递归头尾模式匹配
这是一个示例scala代码-Scala递归头尾模式匹配,scala,pattern-matching,Scala,Pattern Matching,这是一个示例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但我不明白这是如何工作的,有人能帮我理解递归是如何工作的吗?foo当作为参数ls传递的列表为Nil(空)时终止 每次调用foo,ls都会通过模式匹配提取头部(hd)和尾部(t
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但我不明白这是如何工作的,有人能帮我理解递归是如何工作的吗?foo
当作为参数ls
传递的列表为Nil
(空)时终止
每次调用foo
,ls
都会通过模式匹配提取头部(hd
)和尾部(tl
)。head与下一个foo
调用相乘,该调用只取列表的尾部(以及将n
值减去1)
当计算
foo(7,List(1,2,-2,2))
时,下一步是1*foo(6,List(2,-2,2))
等等…因为我不完全确定你在问什么,这可能太复杂了
在匹配中
:
将匹配(且仅匹配)一个空列表case Nil
将破坏列表的结构(其工作方式/原因的确切机制超出了本答案的范围),值case hd::tl
是列表的第一个元素,值hd
是包含第一个元素之后的每个元素的列表tl
:List(foo(7,List(1,2,-2,2))
)非空,因此第二个match子句匹配,结果为空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)
:当乘以时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
尽管对于
列表
,它将比递归实现慢(如长度
和产品
都将完全遍历列表).我已将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匹配{
案例无=>
println(s“${printMul(prev)}$n”)
N
案例hd::tl=>
println(s“${printMul(prev)}$hd*foo(${n-1},$tl)”)
hd*foo(n-1,tl,上一个:+hd)
}
//=======输出======
/*
1*foo(6,列表(2,-2,2))
1*2*foo(5,列表(-2,2))
1*2*-2*foo(4,列表(2))
1*2*-2*2*foo(3,List())
1 * 2 * -2 * 2 * 3
*/
这是rec,但不是tailrec for meth还有一些实现是尾部递归的(即编译器将它们转换为循环),并且使用foldLeft
:两者都需要一个辅助值。