tabulators
Stephen Weeks
MLton@sourcelight.com
Thu, 24 Jan 2002 12:03:14 -0800
> Do you really mean without any side-effects (array updates, ref cells,
> etc.)? And the other question is whether you mean inside the Basis
> Library (where you've got unsafe array and vector operations) or outside
> the Basis Library?
I don't have any better ideas than your code.
outside the basis, with no side effects:
use a list and reverse at the end
(although it would be better to do
Vector.rev o Vector.fromList
instead of
Vector.fromList o List.rev)
outside the basis, with side effects:
use an array, convert to a vector at the end
inside the basis, with side effects and unsafe ops
use an array, coerce to a vector at the end
> Here's a direct conversion from S7 to S1
Makes sense.
> Those all seem fine to me. Although, I'm still not quite clear on the
> advantages of a tabulator over an unfolder, and how one is supposed to
> recognize the right place to use a tabultor.
There are two orthogonal choices.
1. Whether to construct or destruct the vector.
2. Whether the vector library controls the stack or not.
Here is what we've got for those
stack not
------ ---------
construct unfold tabulator
destruct fold iterate
We don't have iterate yet, but I'm thinking about it. The advantage
of a tabulator over an unfolder is that the tabulator allows someone
else to control the stack while the vector is being constructed. So,
for example, if you want to convert a tree in preorder traversal to a
vector, it is easy with a tabulator, but not with an unfolder, because
you must reify the tree traversal stack into state.
Another way to see the difference is that it is easy to convert from
an implementation of tabulators to unfolders, but not vice versa.
--------------------------------------------------------------------------------
signature TABULATOR =
sig
type 'a t
datatype 'a tab = Done of 'a t | More of 'a -> 'a tab
val tabulator: int -> 'a tab
end
signature UNFOLD =
sig
type 'a t
val unfold: int * 'b * ('b -> 'a * 'b) -> 'a t
end
functor TtoU (S: TABULATOR): UNFOLD =
struct
type 'a t = 'a S.t
fun unfold (n, b, f) =
let
fun loop (t, b) =
case t of
S.Done v => v
| S.More g =>
let
val (a, b) = f b
in
loop (g a, b)
end
in
loop (S.tabulator n, b)
end
end
--------------------------------------------------------------------------------
The only way I know how to go the other direction in general is to use
coroutines.
BTW, I dislike the name "tabulator", since it is too close to
"tabulate", which we use for a special case of unfold. I would be
happy to hear suggestions for another name. Maybe just "construct",
since it is the most general kind of constructor (that I know of)?