Cannot call `std.range.chain` with ranges of range of same ultimate element type
import std.algorithm : map;
import std.range : chain, front, iota, ElementType;
immutable string Letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
void main () {
// Range of string
auto str = iota(20).map!(v => Letters[v .. $]);
// Range of range of string
auto ror = iota(10).map!(v => str.save);
string[][] equiv = [ ["A", "B"], ["C", "D"] ];
pragma(msg, ElementType!(typeof(ror)), " -- ", ElementType!(typeof(equi\
v)));
pragma(msg, ElementType!(typeof(ror.front)), " -- ", ElementType!(typeo\
f(equiv.front)));
auto result = chain(ror, equiv);
}
Yields the error:
% ldc2 ror.d
MapResult!(__lambda_L8_C30, Result) -- string[]
string -- string
ror.d(14): Error: template `chain` is not callable using argument types `!()(MapResult!(__lambda_L10_C30, Result), string[][])`
auto result = chain(ror, equiv);
^
/home/mlang/dlang/ldc-1.41.0/bin/../import/std/range/package.d(977): Candidate is: `chain(Ranges...)(Ranges rs)`
with `Ranges = (MapResult!(__lambda_L10_C30, Result), string[][])`
must satisfy the following constraint:
` !is(CommonType!(staticMap!(ElementType, staticMap!(Unqual, Ranges))) == void)`
auto chain(Ranges...)(Ranges rs)
^
I expect it to work, since ror is essentially a range of string, but the CommonType check seems to be too restrictive for this.
What return type do you expect chain(ror, equiv).front to have in this scenario?
Something that is a range of strings.
This would be very complicated to do. f we're expecting ranges of ranges to work, I quess we should to support ranges of any dimensionality.
I believe the return type of chain(ror, equiv).front would be ChooseResult!(typeof(ror.front), typeof(equiv.front)). But then what would it be for chain(roror, equiv).front? I'm already not sure, let alone if we add even more dimensions.
I dont think this should work with default chain; there should be more effort to not break sensible return types
This should only work if sumtypes in general are supported; which would look like this:
import std;
immutable string Letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
auto sumtypechain(R1,R2)(R1 r1,R2 r2){
struct range{
R1 r1;R2 r2;
alias E=SumType!(ElementType!R1,ElementType!R2);
auto front()=>r1.empty?E(r2.front):E(r1.front);
void popFront(){
if( ! r1.empty){
r1.popFront;
} else {
r2.popFront;
}}
bool empty()=>r1.empty&&r2.empty;
}
return range(r1,r2);
}
unittest{
sumtypechain("abc",[1,2,3]).writeln;
}
unittest{
// Range of string
auto str = iota(20).map!(v => Letters[v .. $]);
// Range of range of string
auto ror = iota(10).map!(v => str.save);
string[][] equiv = [ ["A", "B"], ["C", "D"] ];
pragma(msg, ElementType!(typeof(ror)), " -- ", ElementType!(typeof(equiv)));
pragma(msg, ElementType!(typeof(ror.front)), " -- ", ElementType!(typeof(equiv.front)));
auto result = sumtypechain(ror, equiv);
result.writeln;
}
auto mapchain(alias F,Rs...)(Rs rs){
return mixin((){
string output="chain(";
foreach(I;0..Rs.length){
output~="rs["~I.to!string~"].map!F,";
}
output~=")";
return output;
}());
}
auto sumtypechain(Rs...)(Rs rs){
//alias E=SumType!(staticMap!(ElementType,Rs));
alias E=SumType!(NoDuplicates!(staticMap!(ElementType,Rs)));//snar this requirment is bad design
return mapchain!(a=>E(a))(rs);
}
unittest{
sumtypechain("abc",[1,2,3],iota(0,100),[13.37,4.20]).writeln;
}
another idea; I think you could justify "mapchain"