tabulators
Matthew Fluet
fluet@cs.cornell.edu
Tue, 5 Feb 2002 12:24:57 -0500 (EST)
> ------------------------------------------------------------
> signature ITERATE =
> sig
> type 'a t
> datatype 'a iter = Iter of unit -> ('a * 'a iter) option
> val iterate: 'a t -> 'a iter
> val length: 'a t -> int (* for later *)
> end
>
> signature CONSTRUCT =
> sig
> type 'a t
> datatype 'a cons = Done of 'a t | More of 'a -> 'a cons
> val construct: int -> 'a cons
> end
> ------------------------------------------------------------
Random thought that occured to me. CONSTRUCT and ITERATE (when
implemented from within the basis) allow efficient implementations of
"multiple mappers" like
val mapTo2: 'a t * ('a -> ('b * 'c)) -> ('b t * 'c t)
which is something I've often been irked by when writing SSA passes when I
need to make wrapper/router functions where I alpha-vary an argument list
and then need to extract just the Var.t's for a Goto.
E.g., in the SSA restore pass, when I need to introduce new
HandlerPush/Pop's, I need a new handler block with the same type as the
original handler block, that does the new HandlerPush, and then passes all
of it's arguments unchanged to the original handler block:
val newArgs = Vector.map(args, fn (x, ty) => (Var.new (), ty))
val gotoArgs = Vector.map(newArgs, #1)
or
val newgotoArgs = Vector.map(args, fn (x, ty) => let val y = Var.new ()
in ((y, ty), y)
end)
val (newArgs, gotoArgs) = Vector.unzip args
both of which obviously need two passes over a vector. But
val (newArgs, gotoArgs) = Vector.mapTo2
(args, fn (x, ty) => let val y = Var.new ()
in ((y, ty), y)
end)
could be done with one pass.
As a side comment, while we could certainly add mapTo2 to the Vector
structure as things exist now, I actually think that from a design
stand-point it doesn't belong there. A quick look at the signature
suggests that just about everything there can be done with exactly one
pass over the input vector and directly accumulate the result (as in a
fold) or simultaneously produce the result vector (using unfoldi). So,
adding something like mapTo2 gives the "illusion" that it is more
efficient than it really is.
Even further afield, I am somewhat irked by the fact that I can't write a
signature like:
val map{N}To{M} : ('a1 t * ... * 'a{N} t * 'a -> ('b1 * ... * 'b{M})) ->
('bt t * ... * 'b{M} t)
and be able to use map1To3 and map10To2 without changing the library
and/or making some "arbitrary" choice of what functions should be provided
by the library.