[challenge] Lazy flatten/avoiding type forward reference with map

David Nadlinger code at klickverbot.at
Thu Oct 31 12:09:03 PDT 2013


A while back, somebody raised the topic of implementing a lazy 
range for traversing/flattening a tree structure on #d.

The obvious (in terms of Phobos primitives) solution would be 
something along the lines of this:
---
struct Node(T) {
    T val;
    Node!T[] children;
}

auto flatten(T)(Node!T root) {
    import std.algorithm, std.range;
    return only(root.val).chain(map!flatten(root.children).joiner);
}

void main() {
    alias N = Node!int;
    auto a = N(1, [
       N(2, [
          N(3, [
             N(4)
          ])
       ]),
       N(5)
    ]);

    import std.stdio;
    writeln(a.flatten); // [1, 2, 3, 4, 5]
}
---

But of course, that piece of code does not compile with current 
DMD, as the return type of flatten() can't refer to the function 
itself (during name mangling).

Now, one way around this would be to add an array() call at the 
end of the return statement, which hides the type of map!flatten, 
but at the cost of many unnecessary memory allocations. A second 
option would be to use inputRangeObject to convert the return 
value to ForwardRange!T (well, that is if it actually worked, due 
to an implementation bug it leads to a runtime crash).

But can you think of a more simple/elegant workaround?

(Note aside: Obviously, the fact that the code relies on 
recursion might be an issue, and a simple opApply-based solution 
with a worklist stack would likely perform better. Still, I think 
it's a simple, yet interesting problem.)

David


More information about the Digitalmars-d-learn mailing list