0

I'm trying to find the largest value of a list using tail recursion. I can't use any auxiliary functions, though...so it must be done using recursion. I've written a function to find the max, starting from the head, but don't know how to implement it starting from the tail!

lmax []  = error "empty list"
lmax [x] = x
lmax (x::y::xs) = 
  if x > y then lmax (x::xs)
  else          lmax (y::xs)
  • With other questions related to "finding the maximum integer in a list" popping up, this smells of a homework assignment. Don't use Stack Overflow for brainless copy-pasting. Ask intelligent questions. – sshine Sep 20 '13 at 11:28

3 Answers3

2

The term "tail recursion" has nothing to do with the tail of a list, it is about the position of a function call.

You could say that a function call is in tail position, or that it is a tail call, if it's the last thing to happen in a function, i.e. no other computations depend on it.

Compare

fun foo xs = List.length xs

and

fun bar xs = 1 + List.length xs

In the first, the call to List.length is in tail position, because its result is returned immediately.
In the second, since we add 1 to the length, the call isn't a tail call.

"Tail recursion" is when a recursive function call is a tail call.

So you're in luck: your function already is tail recursive, since both conditional branches just return the value of a recursive call.

molbdnilo
  • 64,751
  • 3
  • 43
  • 82
0
fun lmax l = let
  fun lmaxh [] a = a
    | lmaxh (x::xs) a = lmax xs Int.max(x,a)
  in
    lmaxh l 0
  end

This works, assuming that the values are nonnegative integers.

qaphla
  • 4,707
  • 3
  • 20
  • 31
0

Implementing tail recursion optimizes efficiency, because one doesn't have to evaluate and "pop-off" the stack after creating the recursive calls.

In general, to use tail-recursion, you must store some "memory" from prior computations to compare with in the current one, and update it for future computations, so as to immediately exit the function in the base case.

As such, your function is already tail recursive.

However, here is a tail-recursive maxList function, more in the spirit of 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

Your function is written in a very Haskell-like syntax with different cases handled on different lines without being explicitly declared as nested cases inside a function definition. This is quite alright, but is usually not done in SML.