[MLton] MLton.Vector.create

Stephen Weeks MLton@mlton.org
Tue, 28 Mar 2006 13:36:18 -0800


> You can't quite always do what you want before calling the create
> without using a ref cell and perhaps an extra option.  If I need to
> use some function closed over sub or update, and that is what the
> tabulator is going to use, then I would have to use a ref cell
> carrying an option type and fill it in the first time that the
> tabulator was called.

Good point.

> Funny, I think that you convinced me that the currying in the
> tabulator should stay.  The computation being staged could be
> useful, and also implies that the sub and update functions don't
> vary between different invocations of the tabulator.

Well, they sort-of don't vary.  There is a ref cell for the limit
under the hood that does get mutated, and this affects the meaning of
sub and update.

> Ah yes, I was just thinking of the second version, where you pass
> sub/update once and get back a tuple of the tabulator and a whacker.
> I definitely like this one much more.  It makes it clear that there
> is only one sub/update, it being the same for all invocations of the
> tabulator and the whacker.  It lets you stage things in a perhaps
> useful way (building closures and data structures once that are used
> both by the tabulator and the whacker).

All true.  I now agree that this version seems best.  Here's the
signature and implementation that I have committed.

      val create:
         int * ({sub: int -> 'a, update: int * 'a -> unit}
                -> (int -> 'a) * (unit -> unit))
         -> 'a vector

      fun create (n, f) =
         let
            val a = Primitive.Array.array n
            val subLim = ref 0
            fun sub i =
               if Primitive.safe andalso Primitive.Int.geu (i, !subLim) then
                  raise Subscript
               else
                  Primitive.Array.sub (a, i)
            val updateLim = ref 0
            fun update (i, x) =
               if Primitive.safe andalso Primitive.Int.geu (i, !updateLim) then
                  raise Subscript
               else
                  Primitive.Array.update (a, i, x)
            val (tab, finish) = f {sub = sub, update = update}
            val () =
               Util.naturalForeach
               (n, fn i =>
                (Primitive.Array.update (a, i, tab i);
                 subLim := i + 1;
                 updateLim := i + 1))
            val () = finish ()
            val () = updateLim := 0
         in
            fromArray a
         end