回

07 / 17 · Lists and Patterns

尾递归

递归调用如果是「做完才能返回」,栈会跟着列表长。

sum 在递归回来之后还要做加法,所以不是尾调用。列表一长,栈就深。

sum_tr 把还没加完的数放进 acc,递归调用就是整个函数体。编译器可以把这种调用收成循环。两种写法对短列表结果一样,差在大列表会不会爆栈。

例子

utop
let rec sum xs =
  match xs with
  | [] -> 0
  | hd :: tl -> hd + sum tl
val sum : int list -> int = <fun>
let rec sum_tr xs acc =
  match xs with
  | [] -> acc
  | hd :: tl -> sum_tr tl (acc + hd)
val sum_tr : int list -> int -> int = <fun>
sum [1; 2; 3; 4]
- : int = 10
sum_tr [1; 2; 3; 4] 0
- : int = 10

改一改

改完再跑

解释器覆盖书前半的核心:函数、标签参数、模式、记录、变体、ref、模块,以及简化的 Map 和 JSON。没有 GADT 细化、Async 和独立编译。

先预测,再对照

1 / 2

哪一个是尾递归?

2 / 2

sum_tr [1; 2; 3; 4] 0 的结果?

在书里读 Lists and Patterns