Hacker News new | ask | show | jobs
by tom_mellior 3356 days ago
> 2. Tail recursion doesn't really make much of a difference for walking trees, which is recursive, but (mostly) not tail recursive.

Unless you, as the article notes, "know how to take advantage of it". Here's a fully tail-recursive binary tree traversal in OCaml:

    type 'a tree = Leaf of 'a | Branch of 'a tree * 'a tree

    let iter f tree =
      let rec iter_rec f worklist tree =
        match tree with
        | Leaf a ->
          (* Perform the action on this element. *)
          f a;
          (* Consult the worklist for more things to do. *)
          begin match worklist with
          | [] -> ()
          | next_tree::worklist' -> iter_rec f worklist' next_tree
          end
        | Branch (left, right) ->
          (* Visit the left subtree, save the right for visiting later. *)
          iter_rec f (right::worklist) left
      in
      iter_rec f [] tree
Usage example:

    let mytree =
      Branch (Branch (Leaf 1, Leaf 2),
              Branch (Leaf 3, Branch (Leaf 4, Leaf 5)))

    let () = iter (Printf.printf "%d\n") mytree
Yes, people do write traversals like this in OCaml, though with less verbosity than this example I whipped up.

> 3. OCaml in particular uses 63/31-bit ints due to implementation details, which isn't a good fit for 64/32-bit integers.

I think the article means here that you just use int for all the kinds of numerical identifiers that compilers give to things like instructions, basic blocks, pseudo-registers, etc., without doing the kind of micro-optimization that C++ programmers would do, guessing whether the number of blocks is safe to store in an unsigned short etc.

For representing constants from the program, which is what you seem to be referring to, the article does suggest using bignums, not OCaml's native ints.

1 comments

> Unless you, as the article notes, "know how to take advantage of it". Here's a fully tail-recursive binary tree traversal in OCaml:

This is a depth-first search with an explicit stack (the stack is tree :: worklist). You can do the same in an imperative language. Tail recursion here is only an extra-complicated way of writing a simple loop, and you're adding extra complexity by having two variables to represent the stack. The same code can be written just as (if not more) compactly in an imperative language.

You are correct on all counts. Tail recursion allows you to reap the benefits of imperative programming in a purely functional setting, but only thanks to tail call optimization.