caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
From: Francois Pottier <francois.pottier@inria.fr>
To: caml-list@inria.fr
Subject: Re: [Caml-list] Re: generic programming
Date: Fri, 5 Jul 2002 10:33:23 +0200	[thread overview]
Message-ID: <20020705103323.A14853@pauillac.inria.fr> (raw)
In-Reply-To: <4.3.2.7.2.20020703102610.0248b280@mail.d6.com>; from checker@d6.com on Wed, Jul 03, 2002 at 10:29:09AM -0700

On Wed, Jul 03, 2002 at 10:29:09AM -0700, Chris Hecker wrote:
>
> "Sure. I have a 'problem' example: try to implement STL iterators
> in Caml. I don't have the expertise in Caml: I think this requires
> 'higher order functors'. Several people have attempted this, no one
> has succeeded that I know of."

My memories of STL are vague, but if an iterator is what I think it
is, then implementing one in O'Caml is pretty straightforward. An
iterator is a function that returns a function which maintains a
piece of internal state. There is certainly no need for functors
here!

Here is one for lists:

(* [iterator s] returns a stateful iterator over the list [s]. That is,
   if $s = \{ x_1, x_2, \ldots, x_n \}$, then [iterator s] is a function
   which, when invoked for the $k^{\text{th}}$ time, returns [Some ]$x_k$,
   if $k\leq n$, and [None] otherwise. *)

(* val iterator : 'a list -> (unit -> 'a option) *)

  let iterator list =

    let remainder = ref list in

    let rec next () =
      match !remainder with
      | [] ->
	  None
      | elem :: rest ->
	  remainder := rest;
	  Some elem in

    next

And (more interesting) here is one for trees:

(* [iterator s] returns a stateful iterator over the tree [s]. That is, if
   $s = \{ x_1, x_2, \ldots, x_n \}$, where $x_1 < x_2 < \ldots < x_n$, then
   [iterator s] is a function which, when invoked for the $k^{\text{th}}$
   time, returns [Some ]$x_k$, if $k\leq n$, and [None] otherwise. Such a
   function can be useful when one wishes to iterate over a tree's elements,
   without being restricted by the call stack's discipline.

   Because the call stack is not used to store information about which part
   of the tree remains to be walked, an explicit (heap-allocated) structure
   has to be used. It is defined below. Note that it is essentially a list
   of (element, right-tree) pairs, which corresponds to the information
   which would be stored in the call stack, if it were used.

   It would be possible to implement a straightforward iterator by first
   turning the tree into a list, then walking the list. Our implementation
   is more economical, because it only allocates a structure of size $O(\log
   n)$ (the call stack) at a given time, and because only one walk is
   necessary, thus reaping a small constant time factor. *)

(* val iterator : 'a list -> (unit -> 'a option) *)

  type 'a tree =
    | Empty
    | Node of 'a tree * 'a * 'a tree * int

  type 'a remainder =
    | Nothing
    | ElemThenRightThenParent of 'a * 'a tree * 'a remainder

  let iterator s =

    (* When asked to create an iterator for s, we allocate a piece of state,
       which shall allow the iterator to remember which part of the tree
       remains to be walked. It consists of a tree and a remainder, which are
       to be walked in order. At first, the whole tree [s] has to be walked,
       and there is no remainder.

       Note that [next] does not work in worst-case constant time, since it
       may have to travel arbitrarily far down the current sub-tree's left
       spine. However, it does work in amortized constant time; in other
       words, iterating over a complete tree still takes worst-case linear
       time. *)

    let tree = ref s
    and remainder = ref Nothing in

    let rec next () =
      match !tree, !remainder with
      | Empty, Nothing ->
	  None
      | Empty, ElemThenRightThenParent (elem, right, parent) ->
	  tree := right;
	  remainder := parent;
	  Some elem
      | Node(l, v, r, _), parent ->
	  tree := l;
	  remainder := ElemThenRightThenParent(v, r, parent);
	  next () in

    next

I hope this helps,

-- 
François Pottier
Francois.Pottier@inria.fr
http://pauillac.inria.fr/~fpottier/
-------------------
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


  parent reply	other threads:[~2002-07-05  8:33 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2002-07-03  2:49 [Caml-list] " Oleg
2002-07-03  8:37 ` [Caml-list] " Ketanu
2002-07-03 17:29   ` Chris Hecker
2002-07-03 20:07     ` Oleg
2002-07-03 20:34       ` Alessandro Baretta
2002-07-04 15:33         ` John Max Skaller
     [not found]           ` <3D249B27.5080807@baretta.com>
     [not found]             ` <3D25D27B.2020005@ozemail.com.au>
2002-07-07 20:42               ` Alessandro Baretta
2002-07-08  0:59                 ` John Max Skaller
2002-07-08  7:29                   ` Alessandro Baretta
2002-10-15  0:10         ` Eray Ozkural
2002-07-03 21:55     ` Peter Wood
2002-07-04  2:02       ` james woodyatt
2002-07-04 15:18     ` John Max Skaller
2002-07-05  8:42       ` Francois Pottier
2002-07-05  9:25         ` Xavier Leroy
2002-07-05  9:57           ` Chris Hecker
2002-07-05 13:54             ` Xavier Leroy
2002-07-05 17:59               ` Chris Hecker
2002-07-05 20:31                 ` John Max Skaller
2002-07-05 19:33               ` John Max Skaller
2002-07-05 19:31             ` John Max Skaller
2002-07-05  8:33     ` Francois Pottier [this message]
2002-07-05 23:05       ` Dave Berry
2002-07-08  9:54         ` Francois Pottier
2002-07-08 15:49           ` John Max Skaller
2002-08-02 14:49         ` [Caml-list] Streams Diego Olivier Fernandez Pons
2002-08-02 15:29           ` Alain Frisch
2002-08-03 14:19             ` Diego Olivier Fernandez Pons
2002-07-03  8:42 ` [Caml-list] generic programming Johan Baltié
     [not found]   ` <002301c22270$fb4ca160$2be213c3@youngkouzdra>
     [not found]     ` <20020703092753.M39371@wanadoo.fr>
2002-07-05 10:38       ` Anton Moscal
2002-07-03  9:10 ` Jun P.FURUSE

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=20020705103323.A14853@pauillac.inria.fr \
    --to=francois.pottier@inria.fr \
    --cc=caml-list@inria.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;
as well as URLs for NNTP newsgroup(s).