caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
From: Chris Uzdavinis <chris@atdesk.com>
To: Richard Jones <rich@annexia.org>
Cc: caml-list@inria.fr
Subject: Re: [Caml-list] How to find out if a function is tail recursive?
Date: Thu, 12 Jun 2003 11:14:22 -0400	[thread overview]
Message-ID: <j6n0gne3ap.fsf@explicit.atdesk.com> (raw)
In-Reply-To: <20030612141549.GA14762@redhat.com> (Richard Jones's message of "Thu, 12 Jun 2003 15:15:49 +0100")

Richard Jones <rich@annexia.org> writes:

> let rec range a b =
>   if a > b then []
>   else a :: range (a+1) b
>   ;;
>
> let list = range 1 1000000;;
>
> Printf.printf "length = %d\n" (List.length list);;
>
> Can you tell me why this function isn't tail recursive, and share
> any useful tips on how to tell whether a function is or is not tail
> recursive?

The else clause wants to build a list using the current "a" plus
whatever the recursive invocation returns.  But it can't make its
result until the recursive call completes and returns its result, so
it must hang around for the recursive call to complete.  The 2nd call
pends waiting for the 3rd, the 3rd pends waiting for the 4th, and so
on, until they start unwinding.  Called too many times and you get the
notorious overflow.

To be tail recursive, the current function must be essentially
"finished" before it invokes itself recursively.  Usually, to
implement this you have to pass all of your state to the recursive
call, such that there is nothing left to do in the current function.
When we get to the very end of the recursion, the result is
immideately available, and no unwinding is necessary.  The result is
directly returned to the original caller.

Here is how to do it for your function, which uses an internal
function to help, and passes an accumulator (result) into the next
invocation.  Each call appends to the result when the next call is
made.  The "result" starts out empty and gets filled in one piece at
at a time by the recursive calls.

  let range a b =
    let rec range_helper aa result =
      if aa > b then result
      else range_helper (aa+1) (aa :: result)
    in
      List.rev(range_helper a [])
  ;;

Notice, the tail-recursve version builds the list backwards (because
appends go to the front), so after the internal function completes, we
reverse the list to "fix" it.

-- 
Chris

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


  parent reply	other threads:[~2003-06-12 15:14 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2003-06-12 14:15 Richard Jones
2003-06-12 14:31 ` Paul Steckler
2003-06-12 14:43   ` Luc Maranget
2003-06-12 16:15     ` John Max Skaller
2003-06-12 16:37       ` John Max Skaller
2003-06-13  7:23         ` [Caml-list] This is so nice John Max Skaller
2003-06-12 14:37 ` [Caml-list] How to find out if a function is tail recursive? Wolfgang Müller
2003-06-12 14:49 ` Neel Krishnaswami
2003-06-12 15:14 ` Chris Uzdavinis [this message]
2003-06-12 15:33 ` Brian Hurt

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=j6n0gne3ap.fsf@explicit.atdesk.com \
    --to=chris@atdesk.com \
    --cc=caml-list@inria.fr \
    --cc=rich@annexia.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).