how to store a range transformed by a range function?
H. S. Teoh via Digitalmars-d-learn
digitalmars-d-learn at puremagic.com
Thu Jun 19 13:38:56 PDT 2014
On Thu, Jun 19, 2014 at 08:02:39PM +0000, Vlad Levenfeld via Digitalmars-d-learn wrote:
[...]
> For example, lets say I had a couple of managed arrays of doubles, and
> I had some computational path that, at some point, took these two
> ranges and zipped them before passing them along. At that node (where
> the zip is performed) I'd like to save a struct that, upon request,
> returns a Tuple!(double, double) range populated with the current
> values of the source double[]s. Then anything which uses that struct
> is only exposed to a range of ordered pairs, which fell from the sky
> as far as anything on the client-side of the interface is concerned.
>
> Of course I can't, not right off the bat, because storage requires
> specifying a type to store, and the actual type of a lazy-evaluated
> functional result depends on how it was constructed ("Voldemort types"
> as I've heard them called), so there's no way to, say, keep an array
> of these (unless they all have the same source types and underwent the
> same transformations). So even if I could create such a "midway node"
> struct, I wouldn't have any feasible way to store a set of them.
I've run into this before. The solution is to use a class-based wrapper
from std.range to wrap around the range and expose a uniform external
type:
// Original version (doesn't compile):
auto func(R)(R inputRange) {
if (someCondition)
return inputRange.map!((x)=>x+1);
else
return inputRange.filter!((x) => x > 10);
// Compile error: map() and filter() don't return the
// same type, so the return type of func() cannot be
// determined!
}
// Solution:
import std.range : inputRangeObject;
InputRange!E func(R,E)(R inputRange)
{
if (someCondition)
return inputRangeObject(inputRange.map!((x)=>x+1));
// N.B. the object returned by inputRangeObject
// implements the InputRange!E interface.
else
return inputRangeObject(inputRange
.filter!((x) => x > 10));
// N.B.: this object also implements the same
// InputRange!E interface.
// Since both branches implement the InputRange!E
// interface, we can use that as the uniform external
// type to represent either returned range.
}
This example, of course, illustrates the functional solution to the
problem; in your case, you can just store the InputRange!E interfaces in
your nodes, and you can assign different kinds of ranges to it, as long
as they have a common element type. Exactly which concrete type is
behind the InputRange!E interface reference can be determined at
runtime; it doesn't have to be known at compile-time.
T
--
We are in class, we are supposed to be learning, we have a teacher... Is it too much that I expect him to teach me??? -- RL
More information about the Digitalmars-d-learn
mailing list