Mailing list for all users of the OCaml language and system.
 help / color / mirror / Atom feed
From: David Brown <caml-list@davidb.org>
To: Nicolas Cannasse <warplayer@free.fr>
Cc: Pierre Weis <pierre.weis@inria.fr>,
	Falk Hueffner <falk.hueffner@student.uni-tuebingen.de>,
	caml-list@inria.fr
Subject: Re: [Caml-list] Python's yield, Lisp's call-cc or C's setjmp/longjmp in OCaml
Date: Wed, 17 Dec 2003 21:31:55 -0800	[thread overview]
Message-ID: <20031218053155.GA7333@davidb.org> (raw)
In-Reply-To: <004c01c3c504$62407b80$0274a8c0@PWARP>

On Thu, Dec 18, 2003 at 10:14:19AM +0900, Nicolas Cannasse wrote:

> type 'a tree =
>     |  Node of 'a tree list
>     |  Leaf of 'a
> 
> let rec iterator = function
>     | Node l -> List.iter iterator l
>     | Leaf x -> yield x
> 
> Doing it using a closure is more difficult, since we need to reproduce the
> stack using a data structure. That goes of course for all recursive data
> structures.

Ocaml does help us a bit by sort of having lazy functionality.  Remember
that lazy (expr) is roughly equivalent to (fun () -> expr), and is
equivalent in the case where Lazy.force is only called once.  The
closures are very capable of representing the recursive structure, right
in the closures them selves.

What makes this a little complicated is that your definitions make calls
to things like List.iter, which are not defined for lazy lists.  The
first thing to do, is rewrite your function to just return a list of the
results.  This could be done directly in Haskell, and the lazy
evaluation would give you exactly what you want.

  let rec iterator = function
    | Node l -> List.flatten (List.map iterator l)
    | Leaf x -> [x]

To make this lazy, we need to define our own lazy list type.  This is a
lot cleaner than the implicit closures I posted previously, since the
conversion to lazy form is fairly straightforward.  The thing that makes
this tricky is that we are mixing lazy with regular lists.  First, let's
rewrite the needed list functions (flatten, map, and append)
appropriately for the combination of regular and lazy lists we are
using.

  let rec lazy_map f = function
    | [] -> Nil
    | a::l ->
        let r = f a in
        Pair (r, lazy (lazy_map f l))

  let rec lazy_append l r = match l with
    | Nil -> r
    | Pair (a, ar) ->
        Pair (a, lazy (lazy_append (Lazy.force ar) r))

  let rec lazy_flatten = function
    | Nil -> Nil
    | Pair (l, r) ->
        lazy_append l (lazy_flatten (Lazy.force r))

Now we can directly rewrite your above iterator in a lazy fashion:

  let rec lazy_iterator = function
    | Node l -> lazy_flatten (lazy_map lazy_iterator l)
    | Leaf x -> Pair (x, lazy (Nil))

The following code shows that it indeed works:

  let rec force_iter f = function
    | Nil -> ()
    | Pair (a, l) ->
        f a;
        force_iter f (Lazy.force l)

  let showb () =
    let flat = lazy_iterator sample_tree in
    force_iter (fun x -> printf "%d," x) flat;
    printf "\n"

  let () = showb ()

Coming up with some good lazy data structures (lists are often enough)
and possibly some ocamlp4 grammar to make them as easy to use as regular
lists would be sufficient for this kind of problem.

A good exercise would be to rewrite all of this using a
continuation-passing style.

Dave

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


  reply	other threads:[~2003-12-18  5:32 UTC|newest]

Thread overview: 25+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2003-12-16 13:13 Nuutti Kotivuori
2003-12-16 13:28 ` Oleg Trott
2003-12-18  0:15   ` Nuutti Kotivuori
2003-12-16 13:48 ` Ville-Pertti Keinonen
2003-12-16 15:41   ` Kenneth Knowles
2003-12-16 16:45     ` Richard Jones
2003-12-16 18:36       ` Ville-Pertti Keinonen
2003-12-16 18:42 ` Brian Hurt
2003-12-16 18:10   ` Dustin Sallings
2003-12-17  6:30     ` ijtrotts
2003-12-17  8:13       ` Dustin Sallings
2003-12-17 10:35       ` Falk Hueffner
2003-12-17 19:14         ` Pierre Weis
2003-12-17 19:32           ` Falk Hueffner
2003-12-17 20:04           ` David Brown
2003-12-18  1:14           ` Nicolas Cannasse
2003-12-18  5:31             ` David Brown [this message]
2003-12-18  7:05             ` Brian Hurt
2003-12-18  6:45               ` David Brown
2003-12-18 18:44             ` brogoff
2003-12-17 19:42         ` brogoff
2003-12-19 13:39           ` skaller
2003-12-18  0:51       ` Nuutti Kotivuori
2003-12-16 18:06 Kevin S. Millikin
2003-12-18 22:08 Ker Lutyn

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=20031218053155.GA7333@davidb.org \
    --to=caml-list@davidb.org \
    --cc=caml-list@inria.fr \
    --cc=falk.hueffner@student.uni-tuebingen.de \
    --cc=pierre.weis@inria.fr \
    --cc=warplayer@free.fr \
    /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