<?xml version="1.0" encoding="ISO-8859-1"?>

<!DOCTYPE message PUBLIC
  "-//MLarc//DTD MLarc output files//EN"
  "../../mlarc.dtd"[
  <!ATTLIST message
    listname CDATA #REQUIRED
    title CDATA #REQUIRED
  >
]>

  <?xml-stylesheet href="../../mlarc.xsl" type="text/xsl"?>


<message 
  url="2003/11/222e3da9e074f94c1e735e19b5df6c54"
  from="Diego Olivier Fernandez Pons &lt;Diego.FERNANDEZ_PONS@e...&gt;"
  author="Diego Olivier Fernandez Pons"
  date="2003-11-19T16:15:23"
  subject="[Caml-list] try ... with and stack overflow"
  prev="2003/11/27a305d4ac2ed8a10be76517de11a07e"
  next="2003/11/030cefc60478232c72d1ae302af3e813"
  next-in-thread="2003/11/779eaa7390110a825770a5e27a9c68f3"
  prev-thread="2003/11/1f551b7bf53f76d0b573b176d6687798"
  next-thread="2003/11/b9a42a206431fb25d03c3e4bf43cc125"
  root="../../"
  period="month"
  listname="caml-list"
  title="Archives of the Caml mailing list">

<thread subject="[Caml-list] try ... with and stack overflow">
<msg 
  url="2003/11/222e3da9e074f94c1e735e19b5df6c54"
  from="Diego Olivier Fernandez Pons &lt;Diego.FERNANDEZ_PONS@e...&gt;"
  author="Diego Olivier Fernandez Pons"
  date="2003-11-19T16:15:23"
  subject="[Caml-list] try ... with and stack overflow">
<msg 
  url="2003/11/779eaa7390110a825770a5e27a9c68f3"
  from="Brian Hurt &lt;bhurt@s...&gt;"
  author="Brian Hurt"
  date="2003-11-19T16:46:36"
  subject="Re: [Caml-list] try ... with and stack overflow">
</msg>
</msg>
</thread>

<contents>
    Bonjour,

I cannot figure what is puzzling the Caml compiler in some code I
wrote. It seems to be related to the try ... with construction against
tail-recursive optimization. Or am I doing a semantical mistake (that
is to say that I am believing the two codes to be equivalent when they
are not) ?

Some explanations : I first wrote an optimized search procedure (for a
branch and bound) and then wanted to compare it against the naive
version.

It works in the following way :
- goes down the tree by the left branch until reaches a leaf
- if the leaf is a solution, all the inexplorated branches are put in
closures and added to the 'continuation queue'
- if the leaf fails, an exception is raised and the deepest
unexplorated right branch is taken instead (try ... left_branch ...
with Failed -&gt; ... right_branch ...)



exception Failed

type location = Left | Right


(* Optimized depth-first search *)

type 'a goal = Goal of ('a goal list -&gt; 'a * 'a goal list)

let rec solve = function
  | [] -&gt; []
  | Goal g :: tail -&gt;
      try
	let (result, continuations) = g tail in
	  result :: solve continuations
      with Failed -&gt; solve tail

let rec dfs continuations = fun f data level -&gt;
  match level with
    | 0 -&gt; (f data, continuations)
    | n -&gt;
	try
	  let
              right = Goal (fun c -&gt; dfs c f (Right :: data) (n - 1))
          in
	    dfs (right :: continuations) f (Left :: data) (n - 1)
	with Failed -&gt; dfs continuations f (Right :: data) (n - 1)

let make_dfs = fun f n -&gt; Goal (function c -&gt; dfs c f [] n)


The naive version works in the same way but closures are
systematically constructed for both left and right branches.


(* Simple depth-first search *)


type 'a simpleGoal =
  | Result of 'a
  | Closure of ('a simpleGoal list -&gt; 'a simpleGoal list)

let rec simple_solve = function
  | [] -&gt; []
  | Result x :: tail -&gt; x :: simple_solve tail
  | Closure f :: tail -&gt;
      try
	simple_solve (f tail)
      with Failed -&gt; simple_solve tail

let rec simple_dfs continuations = fun f data level -&gt;
  match level with
    | 0 -&gt; Result (f data) :: continuations
    | n -&gt;
 let
   left = Closure (fun c -&gt; simple_dfs c f (Left :: data) (n - 1)) and
   right = Closure (fun c -&gt; simple_dfs c f (Right :: data) (n - 1))
 in
    left :: right :: continuations

let make_simple_dfs = fun f n -&gt;
  Closure (function c -&gt; simple_dfs c f [] n)


Both seem to be working well

let rec print_location = function
  | [] -&gt; ()
  | Left :: tail -&gt; print_location tail ; print_string "Left  "
  | Right :: tail -&gt; print_location tail ; print_string "Right "

let all_fail_trace = function location -&gt;
  print_location location ;
  print_newline();
  raise Failed

# solve [make_dfs all_fail_trace 2];;
Left  Left
Left  Right
Right Left
Right Right
- : '_a list = []

# simple_solve [make_simple_dfs all_fail_trace 2];;
Left  Left
Left  Right
Right Left
Right Right
- : '_a list = []

But the naive version seems to have a tail-recursion problem

# solve [make_dfs (fun loc -&gt; raise Failed) 15];;
- : '_a list = []

# simple_solve [make_simple_dfs (fun loc -&gt; raise Failed) 15];;
Stack overflow during evaluation (looping recursion?).


Then I changed the following code


let rec simple_solve = function
  | [] -&gt; []
  | Result x :: tail -&gt; x :: simple_solve tail
  | Closure f :: tail -&gt;
      try
	simple_solve (f tail)
      with Failed -&gt; simple_solve tail

by

  | Closure f :: tail -&gt;
      simple_solve (try
                        f tail
                    with Failed -&gt; tail)

and this time it worked

# solve [make_dfs (fun loc -&gt; raise Failed) 15];;
- : '_a list = []

# simple_solve [make_simple_dfs (fun loc -&gt; raise Failed) 15];;
- : '_a list = []


    Diego Olivier

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

</contents>

</message>

