* 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