如何以递归方式合并两个列表?

时间:2016-10-27 14:33:11

标签: ats

例如,可以调用以下函数merge来合并两个给定的整数列表:

fun
merge
{m,n:nat}
(
xs: list(int, m)
,
ys: list(int, n)
) : list(int, m+n) =
(
  case+ xs of
  | list_nil() => ys
  | list_cons(x, xs2) =>
    (
      case+ ys of
      | list_nil() => xs
      | list_cons(y, ys2) =>
          if x <= y
            then list_cons(x, merge(xs2, ys))
            else list_cons(y, merge(xs, ys2))
          // end of [if]
    )
)

显然,merge不是尾递归的。如果应用于两个非常长的列表,merge可能会溢出调用堆栈。有没有办法实现merge尾递归?

1 个答案:

答案 0 :(得分:1)

请注意,stream2list_vt是尾部重复的(并且非常节省内存):

fun
merge
{m,n:nat}
(
xs: list(int, m)
,
ys: list(int, n)
) : List0_vt(int) = stream2list_vt(merge2(xs, ys))

and
merge2
{m,n:nat}
(
xs0: list(int, m)
,
ys0: list(int, n)
) : stream_vt(int) = $ldelay
(
  case+ xs0 of
  | list_nil() =>
    !(streamize_list_elt(ys0))
  | list_cons(x0, xs1) =>
    (
      case+ ys0 of
      | list_nil() =>
        !(streamize_list_elt(xs0))
      | list_cons(y0, ys1) =>
        if x0 <= y0
          then stream_vt_cons(x0, merge2(xs1, ys0))
          else stream_vt_cons(y0, merge2(xs0, ys1))
        // end of [if]
    )
)

当然,有一种更有效的方法来实现merge尾递归,而不是上面给出的方法。但是,这个使用线性流的示例显示了一种简单而系统的方式来逐尾递归地构建列表。