[MLton-user] Iterator
Stephen Weeks
sweeks@sweeks.com
Thu, 4 Mar 2004 19:29:54 -0800
> I'd like to program an iterator/coroutine/lazy list - I have a data
> structure and want to provide a list-like interface to the contents, but
> the list elements should only be generated on demand.
>
> What's the most *efficient* way to do this in MLTon? I couldn't find
> direct support for lazy evaluation. The continuation docs mention time
> proportional to stack size, which looks nasty. Should I use threads? Or
> am I making life too complicated and should I code something directly
> using a mutable reference (I'm used to programming in Haskell, so that
> last thought only just occurred to me, but I'm guessing it's the way to
> go)?
You could use threads, which won't be as slow as continuations, but
that's probably overkill, and will still be a lot slower than function
calls. My bet is the right thing to do is to reify the stack
yourself. As an example, consider the following code that converts a
tree to a sequence.
--------------------------------------------------------------------------------
structure Seq =
struct
datatype 'a t = T of unit -> ('a * 'a t) option
val dest: 'a t -> ('a * 'a t) option =
fn (T f) => f ()
fun empty (): 'a t = T (fn () => NONE)
end
structure Tree =
struct
datatype 'a t =
Empty
| Node of {left: 'a t,
right: 'a t,
value: 'a}
fun toSeq (t: 'a t): 'a Seq.t =
let
fun force (t: 'a t, rest: 'a Seq.t): ('a * 'a Seq.t) option =
case t of
Empty => Seq.dest rest
| Node {left, right, value} =>
force (left,
Seq.T (fn () => SOME (value, delay (right, rest))))
and delay (t: 'a t, rest: 'a Seq.t): 'a Seq.t =
Seq.T (fn () => force (t, rest))
in
delay (t, Seq.empty ())
end
end
--------------------------------------------------------------------------------
If you need, you can make the resulting sequence lazy by memoizing the
thunk in delay with a mutable reference. It depends on the complexity
of the data structure and how many times you walk the sequence as to
whether that's worth it.