使用尾递归查找最大值

时间:2013-09-19 03:58:36

标签: functional-programming sml smlnj

我正在尝试使用尾递归查找列表的最大值。我不能使用任何辅助功能,但是......所以必须使用递归来完成。我已经编写了一个函数来查找最大值,从头开始,但不知道如何从尾部开始实现它!

lmax []  = error "empty list"
lmax [x] = x
lmax (x::y::xs) = 
  if x > y then lmax (x::xs)
  else          lmax (y::xs)

3 个答案:

答案 0 :(得分:2)

术语“尾递归”与列表的尾部无关,它与函数调用的位置有关。

你可以说函数调用处于尾部位置,或者它是尾调用,如果它是函数中发生的最后一件事,即没有其他计算依赖于它。

比较

fun foo xs = List.length xs

fun bar xs = 1 + List.length xs

在第一个中,对List.length的调用处于尾部位置,因为其结果立即返回 在第二个中,因为我们在长度上加1,所以调用不是尾调用。

“Tail recursion”是指递归函数调用是尾调用。

所以你很幸运:你的函数已经是尾递归的,因为两个条件分支只返回递归调用的值。

答案 1 :(得分:0)

fun lmax l = let
  fun lmaxh [] a = a
    | lmaxh (x::xs) a = lmax xs Int.max(x,a)
  in
    lmaxh l 0
  end

这是有效的,假设值是非负整数。

答案 2 :(得分:0)

实现尾递归可以优化效率,因为在创建递归调用之后,不必评估和“弹出”堆栈。

通常,要使用尾递归,必须存储先前计算中的一些“内存”以与当前计算中的内存进行比较,并更新它以供将来的计算使用,以便立即退出基本情况中的函数。

因此,你的函数已经尾递归。

但是,这是一个尾递归maxList函数,更符合SML的精神:

fun maxList l =
   let 
      fun maxListHelper l acc = 
         case l of 
             [] => acc
           | x :: xs' => if x > acc 
                         then (maxListHelper xs' x) 
                         else (maxListHelper xs' acc)
   in
     case l of
         [] => error "Empty List!"
       | x :: xs' => maxListHelper xs' x
   end

您的函数是用非常类似Haskell的语法编写的,不同的案例在不同的行上处理,而不是在函数定义中将显式声明为嵌套的案例。这很好,但通常不是在SML中完成的。