Thread overview | |||||||
---|---|---|---|---|---|---|---|
|
March 28, 2014 Choice ranges? | ||||
---|---|---|---|---|
| ||||
Today I ran into an interesting situation where I have a function f that needs to return ranges of different types (but identical element types):
auto f(A...)(A args) {
...
if (someCondition)
return cartesianProduct(x, y)
.joiner;
else
return cartesianProduct(x, y)
.joiner
.filter!someFilter;
}
This obviously can't compile, because the return types are not the same. (Note that someCondition is only known at runtime.) But abstractly speaking, it *should* work, because the element type of the returned range is identical.
So how would I implement something like this?
T
--
The fact that anyone still uses AOL shows that even the presence of options doesn't stop some people from picking the pessimal one. - Mike Ellis
|
March 28, 2014 Re: Choice ranges? | ||||
---|---|---|---|---|
| ||||
Posted in reply to H. S. Teoh | On Friday, 28 March 2014 at 19:02:48 UTC, H. S. Teoh wrote:
> Today I ran into an interesting situation where I have a function f that
> needs to return ranges of different types (but identical element types):
>
> auto f(A...)(A args) {
> ...
> if (someCondition)
> return cartesianProduct(x, y)
> .joiner;
> else
> return cartesianProduct(x, y)
> .joiner
> .filter!someFilter;
> }
>
> This obviously can't compile, because the return types are not the same.
> (Note that someCondition is only known at runtime.) But abstractly
> speaking, it *should* work, because the element type of the returned
> range is identical.
>
> So how would I implement something like this?
>
>
> T
You could try using std.variant.Algebraic. I've used it successfully before, but it's a bit clumsy and out of date.
|
March 28, 2014 Re: Choice ranges? | ||||
---|---|---|---|---|
| ||||
Posted in reply to H. S. Teoh | H. S. Teoh:
> So how would I implement something like this?
One option is to wrap those ranges in classes. See std.range for the adapters. (I have not used them yet).
Bye,
bearophile
|
March 28, 2014 Re: Choice ranges? | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | On 03/28/2014 01:46 PM, bearophile wrote: > H. S. Teoh: > >> So how would I implement something like this? > > One option is to wrap those ranges in classes. See std.range for the > adapters. (I have not used them yet). Link: http://dlang.org/phobos/std_range.html#.inputRangeObject Short examples here as well under "Run-time polymorphism with inputRangeObject() and outputRangeObject()": http://ddili.org/ders/d.en/ranges_more.html <quote> inputRangeObject() is flexible enough to support all of the non-output ranges: InputRange, ForwardRange, BidirectionalRange, and RandomAccessRange. Because of that flexibility, the object that it returns cannot be defined by auto. </quote> Ali |
March 29, 2014 Re: Choice ranges? | ||||
---|---|---|---|---|
| ||||
Posted in reply to H. S. Teoh | On 03/28/2014 08:00 PM, H. S. Teoh wrote: > Today I ran into an interesting situation where I have a function f that > needs to return ranges of different types (but identical element types): > > auto f(A...)(A args) { > ... > if (someCondition) > return cartesianProduct(x, y) > .joiner; > else > return cartesianProduct(x, y) > .joiner > .filter!someFilter; > } > > This obviously can't compile, because the return types are not the same. > (Note that someCondition is only known at runtime.) But abstractly > speaking, it *should* work, because the element type of the returned > range is identical. > > So how would I implement something like this? > > > T > The following is as close as I got. I think the definite initialization checks DMD implements are horribly broken for union fields. import std.range, std.algorithm, std.typetuple, std.traits; template CommonElementType(T...)if(allSatisfy!(isInputRange,T)){ alias CommonElementType = CommonType!(staticMap!(ElementType,T)); } private template Neg(alias a){ enum Neg(T...)=!a!T; } struct SumRange(T...)if(allSatisfy!(isInputRange,T)&&!is(void==CommonElementType!T)&&allSatisfy!(Neg!hasElaborateDestructor,T)&&allSatisfy!(Neg!hasElaborateCopyConstructor,T)){ size_t tag; private union{ T rs=void; } // private this(); @property front()@trusted{ switch(tag){ foreach(i,_;T) case i: return rs[i].front; default: assert(0); } } @property bool empty()@trusted{ switch(tag){ foreach(i,_;T) case i: return rs[i].empty; default: assert(0); } } void popFront()@trusted{ switch(tag){ foreach(i,_;T) case i: return rs[i].popFront(); default: assert(0); } } } private T buildSum(T, size_t tag,S)(S arg)@trusted{ T r; r.tag=tag; r.rs[tag]=arg; return r; } auto inl(T,S)(S arg)if(!hasElaborateDestructor!S&&!hasElaborateDestructor!T&&!hasElaborateCopyConstructor!S&&!hasElaborateCopyConstructor!T){ return buildSum!(SumRange!(S,T),0)(arg); } auto inr(S,T)(T arg)if(!hasElaborateDestructor!S&&!hasElaborateDestructor!T&&!hasElaborateCopyConstructor!S&&!hasElaborateCopyConstructor!T){ return buildSum!(SumRange!(S,T),1)(arg); } auto f(R,S)(bool condition,R x,S y){ auto r1(){ return cartesianProduct(x, y).map!(a=>[a.expand]) .joiner; } auto r2(){ return cartesianProduct(x, y).map!(a=>[a.expand]) .joiner .filter!(a=>a>2); } if(condition) return r1().inl!(typeof(r2())); else return r2().inr!(typeof(r1())); } void main(){ import std.stdio; writeln(f(true, [1,2,3], [4,5,6])); writeln(f(false, [1,2,3], [4,5,6])); } |
Copyright © 1999-2021 by the D Language Foundation