Composing blocks
29 December 2011
The original Rust design included iterators very similar to Python’s generators. As I understand it, these were stripped out in favor of Ruby-esque blocks, partially because nobody could agree on the best way to implement iterators. I like blocks, but it seems like it’s more natural to compose iterators, so I wanted to think a bit about how one might use blocks to achieve similar things. I’m sure this is nothing new; there must be hundreds of libraries in Haskell that do the same things I’m talking about here.
A very simple example of what I mean by iterator composition is
Python’s enumerate()
function, which converts an iterator over T
items into an iterator over (uint, T)
pairs, where the uint
represents the index. This handy little function allows any loop to
easily track the index, no matter what it is iterating over. So I can
write:
for (idx, elem) in enumerate(list): ...
for (idx, elem) in enumerate(dict.keys()): ...
for (idx, elem) in enumerate(dict.values()): ...
for (idx, elem) in enumerate(anything at all): ...
This is very useful.
Now, in Rust, we have a function vec::iter()
, defined like so:
fn iter<T>(v: [T], blk: block(T)) {
uint::range(0, vec::len(v)) { |i|
blk(v[i]);
}
}
Suppose that we wanted to write some kind of generic enumerate()
style function that would convert a function like iter
into one
that provides indices. I think the only way to do this in Rust is
to write something like:
fn enumerate<S,T>(iter_fn: block(block(T)), blk: block(uint, T)) {
let i = 0u;
iter_fn() { |t|
blk(i, t);
i += 1u;
}
}
This would then be used like so:
enumerate(bind vec::iter(v, _)) { |i, e| ... }
enumerate(bind m.keys(_)) { |i, e| ... }
enumerate(bind m.values(_)) { |i, e| ... }
Overall, this is not too bad. A lighterweight curry syntax would make
it somewhat more pleasant, but I rather like bind
as it is, so I
don’t have any concrete suggestions. Besides, after my foray into
expanding the possibilities of block sugar in expressions, I am done
with thinking about syntax for a little while!