caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* Mututal Recursion and Tail Recursion
@ 2005-07-13 19:03 Jonathan Bryant
  2005-07-15  6:40 ` [Caml-list] " Jean-Christophe Filliatre
  0 siblings, 1 reply; 4+ messages in thread
From: Jonathan Bryant @ 2005-07-13 19:03 UTC (permalink / raw)
  To: caml-list

[-- Attachment #1: Type: text/plain, Size: 948 bytes --]

Is is possible to have mutually recursive functions that are also tail
recursive?  For example, attached is some code I wrote to flatten a list
of lists using mutually recursive functions.  I've tried this with large
lists (5,000,000+) and have not encountered a stack overflow, but that
does not necessarily mean that tail recursion is happening.

Also, I know that there are ZAM opcodes that indicate a tail recursive
function (TAILCALL, if I am not mistaken) and one or two of the
undocumented compiler options will dump the opcodes.  Could someone
briefly explain what each of those options do so I wouldn't have to take
up everybody's time asking if this is tail recursive?

--Jonathan

-- 
*=========================*
|Jonathan Bryant          |
|Valdosta State University|
|Information Technology   |
|System Operations        |
|-------------------------|
|jtbryant@valdosta.edu    |
|x6358                    |
*=========================*

[-- Attachment #2: list_aux.ml --]
[-- Type: text/plain, Size: 2643 bytes --]

let print l = 
    let rec aux l1 = match l1 with
          []    -> Printf.printf "[]";
        | h::[] -> Printf.printf "%d]" h
        | h::t  -> Printf.printf "%d; " h; aux t in
    Printf.printf "[";
    aux l;;

let print_ll ll =
    let rec aux l1 = match l1 with
          [] -> Printf.printf "[]";
        | h::[] -> print h; Printf.printf "]"
        | h::t -> print h; Printf.printf "; "; aux t in
    Printf.printf "[";
    aux ll;;

let flatten ll =
    let rec flat_out ol oa = match ol with
          []   -> oa
        | h::t -> flat_in h t oa
    and flat_in il ot ia = match il with
          []   -> flat_out ot ia
        | h::t -> flat_in t ot (h::ia) in
    List.rev (flat_out ll []);;

let interpolate l1 l2 =
    let rec inter x y a = match x,y with
          [],[]         -> a
        | [],h::t       -> inter t x (h::a)
        | h::t,[]       -> inter t y (h::a)
        | h1::t1,h2::t2 -> inter y t1 (h1::a) in
    List.rev (inter l1 l2 []);;

let range x m s =
    let rec aux c a = if c > m then a else aux (c + s) (c :: a) in
    List.rev (aux x []);;

let range_ll min max step division =
    let l = range min max step in
    let rec aux1 l1 a1 = match l1 with
          []   -> (List.rev a1)
        | h::t -> aux2 l1 0 [] a1
    and aux2 l2 len a2 a1 =
        if len < division
        then match l2 with
              []   -> aux2 [] division a2 a1
            | h::t -> aux2 t (len + 1) (h::a2) a1
        else aux1 l2 ((List.rev a2)::a1)
    in aux1 l [];;

let _ =
    let min = 1 and max = 5000000 in
    Printf.printf "Generating lists"; flush stdout;
    Printf.printf "."; flush stdout;
    let my_list = range min max 2 in
    Printf.printf "."; flush stdout;
    let my_other_list = range (min + 1) max 2 in
    Printf.printf "."; flush stdout;
    let my_list_list = range_ll min max 1 1 in
    Printf.printf "\n"; flush stdout;
    Printf.printf "\nMy List: "; flush stdout;
    (* print my_list; *)
    Printf.printf "\nMy Other List: "; flush stdout;
    (* print my_other_list; *)
    Printf.printf "\nMy List and My Other List Interpolated: "; flush stdout;
    (* print (interpolate my_list my_other_list); *)
    Printf.printf "\nMy List List: "; flush stdout;
    (* print_ll my_list_list; *)
    Printf.printf "\nMy List List Flattened: "; flush stdout;
    (* print (flatten my_list_list); *)
    Printf.printf "\n\n"; flush stdout;
    if (interpolate my_list my_other_list) = (flatten my_list_list)
    then (
        Printf.printf "The interpolated and flattened lists are equal!\n";
        flush stdout
    ) else (
        Printf.printf "Hmmm...\n";
        flush stdout
    );;

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [Caml-list] Mututal Recursion and Tail Recursion
  2005-07-13 19:03 Mututal Recursion and Tail Recursion Jonathan Bryant
@ 2005-07-15  6:40 ` Jean-Christophe Filliatre
  2005-07-15 12:15   ` Jonathan Bryant
  0 siblings, 1 reply; 4+ messages in thread
From: Jean-Christophe Filliatre @ 2005-07-15  6:40 UTC (permalink / raw)
  To: jtbryant; +Cc: caml-list


Jonathan Bryant writes:
 > Is is possible to have mutually recursive functions that are also tail
 > recursive?  

Yes.

 > For example, attached is some code I wrote to flatten a list
 > of lists using mutually recursive functions.  I've tried this with large
 > lists (5,000,000+) and have not encountered a stack overflow, but that
 > does not necessarily mean that tail recursion is happening.

Looking at the assembly code (obtained with "ocamlopt -S") clearly
gives the answer: all three recursive calls in flat_in and flat_out
are realized by jumps (and not calls). 

I copy below the assembly code for the functions flat_in and flat_out.

Hope this helps,
-- 
Jean-Christophe Filliâtre (http://www.lri.fr/~filliatr)


======================================================================
	.data
	.globl	camlTest__data_begin
camlTest__data_begin:
	.text
	.globl	camlTest__code_begin
camlTest__code_begin:
	.data
	.long	2048
	.globl	camlTest
camlTest:
	.space	8
	.data
	.long	7415
camlTest__1:
	.long	caml_curry2
	.long	5
	.long	camlTest__flat_out_57
	.long	4345
	.long	caml_curry3
	.long	7
	.long	camlTest__flat_in_58
	.text
	.align	16
	.globl	camlTest__flat_in_58
	.type	camlTest__flat_in_58,@function
camlTest__flat_in_58:
.L101:
	movl	%eax, %edx
	cmpl	$1, %edx
	je	.L100
.L102:	movl	caml_young_ptr, %eax
	subl	$12, %eax
	movl	%eax, caml_young_ptr
	cmpl	caml_young_limit, %eax
	jb	.L103
	leal	4(%eax), %esi
	movl	$2048, -4(%esi)
	movl	(%edx), %eax
	movl	%eax, (%esi)
	movl	%ecx, 4(%esi)
	movl	4(%edx), %eax
	movl	%esi, %ecx
	jmp	.L101
	.align	16
.L100:
	movl	%ebx, %eax
	movl	%ecx, %ebx
	jmp	camlTest__flat_out_57
.L103:	call	caml_call_gc
.L104:	jmp	.L102
	.text
	.align	16
	.globl	camlTest__flat_out_57
	.type	camlTest__flat_out_57,@function
camlTest__flat_out_57:
.L106:
	movl	%ebx, %ecx
	cmpl	$1, %eax
	je	.L105
	movl	4(%eax), %ebx
	movl	(%eax), %eax
	jmp	camlTest__flat_in_58
	.align	16
.L105:
	movl	%ecx, %eax
	ret
	.text
	.align	16
	.globl	camlTest__entry
	.type	camlTest__entry,@function
camlTest__entry:
.L107:
	movl	$camlTest__1, %eax
	movl	%eax, %ebx
	addl	$16, %eax
	movl	%ebx, camlTest
	movl	%eax, camlTest + 4
	movl	$1, %eax
	ret
	.text
	.globl	camlTest__code_end
camlTest__code_end:
	.data
	.globl	camlTest__data_end
camlTest__data_end:
	.long	0
	.globl	camlTest__frametable
camlTest__frametable:
	.long	1
	.long	.L104
	.word	4
	.word	3
	.word	5
	.word	3
	.word	7
	.align	4
======================================================================


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [Caml-list] Mututal Recursion and Tail Recursion
  2005-07-15  6:40 ` [Caml-list] " Jean-Christophe Filliatre
@ 2005-07-15 12:15   ` Jonathan Bryant
  2005-07-18  0:56     ` Jacques Garrigue
  0 siblings, 1 reply; 4+ messages in thread
From: Jonathan Bryant @ 2005-07-15 12:15 UTC (permalink / raw)
  To: caml-list

Ok, I don't know enough about assembly to know exactly what that means,
although I think that you mean they are tail recursive.  The whole
reason I wrote this tiny module was to do that tail recursive since the
List module isn't.  How does one submit code updates to INRIA for things
like this?

On Fri, 2005-07-15 at 08:40 +0200, Jean-Christophe Filliatre wrote:
> Jonathan Bryant writes:
>  > Is is possible to have mutually recursive functions that are also tail
>  > recursive?  
> 
> Yes.
> 
>  > For example, attached is some code I wrote to flatten a list
>  > of lists using mutually recursive functions.  I've tried this with large
>  > lists (5,000,000+) and have not encountered a stack overflow, but that
>  > does not necessarily mean that tail recursion is happening.
> 
> Looking at the assembly code (obtained with "ocamlopt -S") clearly
> gives the answer: all three recursive calls in flat_in and flat_out
> are realized by jumps (and not calls). 
> 
> I copy below the assembly code for the functions flat_in and flat_out.
> 
> Hope this helps,
-- 
*=========================*
|Jonathan Bryant          |
|Valdosta State University|
|Information Technology   |
|System Operations        |
|-------------------------|
|jtbryant@valdosta.edu    |
|x6358                    |
*=========================*


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [Caml-list] Mututal Recursion and Tail Recursion
  2005-07-15 12:15   ` Jonathan Bryant
@ 2005-07-18  0:56     ` Jacques Garrigue
  0 siblings, 0 replies; 4+ messages in thread
From: Jacques Garrigue @ 2005-07-18  0:56 UTC (permalink / raw)
  To: jtbryant; +Cc: caml-list

From: Jonathan Bryant <jtbryant@valdosta.edu>

> Ok, I don't know enough about assembly to know exactly what that means,
> although I think that you mean they are tail recursive.  The whole
> reason I wrote this tiny module was to do that tail recursive since the
> List module isn't.  How does one submit code updates to INRIA for things
> like this?

There are already lots of tail-recursive replacements for the List
module, most notably the one included in Extlib. So if you need to
handle very long lists you can already use them.

The common problem for all these replacements is that they are slower
than the original (non tail-recursive) functions, particularly for
short lists, which are the most frequent ones.

So there is no need to submit this code :-)

(But I wonder whether it would not be a good idea to include a
Safelist module in the standard library...)

Cheers,

Jacques Garrigue


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2005-07-18  0:56 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-07-13 19:03 Mututal Recursion and Tail Recursion Jonathan Bryant
2005-07-15  6:40 ` [Caml-list] " Jean-Christophe Filliatre
2005-07-15 12:15   ` Jonathan Bryant
2005-07-18  0:56     ` Jacques Garrigue

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).