Created
September 1, 2011 19:05
-
-
Save MartinNowak/1186982 to your computer and use it in GitHub Desktop.
Range interface List comprehension
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import std.algorithm, std.conv, std.functional, std.stdio, std.range, std.traits, std.typetuple, std.typecons; | |
pragma(importpath, "dranges=https://raw.github.com/dawgfoto/dranges/master"); | |
import dranges.functional; | |
pragma(build, dranges); | |
Permute!Ranges permute(Ranges...)(Ranges ranges) | |
{ | |
return typeof(return)(ranges); | |
} | |
struct Permute(Ranges...) | |
if(Ranges.length | |
&& allSatisfy!(isForwardRange, staticMap!(Unqual, Ranges)) | |
&& !anySatisfy!(isInfinite, staticMap!(Unqual, Ranges)) | |
) | |
{ | |
alias staticMap!(Unqual, Ranges) R; | |
Tuple!(R[1..$]) saved; | |
Tuple!R ranges; | |
alias Tuple!(staticMap!(.ElementType, R)) ElementType; | |
this(R rs) | |
{ | |
foreach (i, Unqual; R[1 .. $]) | |
saved[i] = rs[i + 1].save; | |
foreach (i, Unused; R) | |
ranges[i] = rs[i].save; | |
} | |
ElementType front() | |
{ | |
ElementType result = void; | |
foreach(i, Unused; R) | |
{ | |
auto addr = cast(Unqual!(typeof(result[i]))*) &result[i]; | |
emplace(addr, ranges[i].front); | |
} | |
return result; | |
} | |
bool empty() | |
{ | |
foreach(i, Unused; R) | |
if (ranges[i].empty) | |
return true; | |
return false; | |
} | |
void popFront() | |
{ | |
foreach_reverse(i, Unused; R) { | |
ranges[i].popFront; | |
if (!ranges[i].empty) | |
break; | |
static if (i != 0) | |
ranges[i] = saved[i - 1].save; | |
} | |
} | |
Permute save() | |
{ | |
Permute result = void; | |
emplace(&result.saved, this.saved); | |
foreach(i, Unused; R) | |
emplace(&result.ranges[i], this.ranges[i].save); | |
return result; | |
} | |
} | |
Comp!(prod, cond, Ranges) comp(alias prod, alias cond, Ranges...)(Ranges ranges) { | |
return typeof(return)(ranges); | |
} | |
struct Comp(alias prod, alias cond, Ranges...) | |
{ | |
alias staticMap!(Unqual, Ranges) R; | |
alias naryFun!(prod) produce; | |
alias naryFun!(cond) condition; | |
Permute!Ranges perm; | |
this(R rs) | |
{ | |
perm = permute!Ranges(rs); | |
ensureFront(); | |
} | |
auto front() | |
{ | |
return produce(perm.front.tupleof); | |
} | |
bool empty() | |
{ | |
return perm.empty; | |
} | |
void popFront() | |
{ | |
perm.popFront; | |
ensureFront(); | |
} | |
Comp save() | |
{ | |
Comp result = void; | |
emplace(&result.perm, this.perm.save); | |
return result; | |
} | |
private void ensureFront() | |
{ | |
while (!perm.empty && !condition(perm.front.tupleof)) | |
perm.popFront; | |
} | |
} | |
void main() { | |
writeln( | |
array( | |
comp!(q{a * b}, q{a + b < 15})(iota(100), iota(100)) | |
) | |
); | |
writeln("----------------------------------------"); | |
// little more verbose but equivalent | |
writeln( | |
array( | |
map!q{a[0] * a[1]}(filter!q{a[0] + a[1] < 15}(permute(iota(100), iota(100)))) | |
) | |
); | |
writeln("----------------------------------------"); | |
writeln( | |
array( | |
comp!(q{a * b * c}, q{a > b && b < c})(iota(10), iota(10), iota(10)) | |
) | |
); | |
writeln("----------------------------------------"); | |
// Haskell | |
// let comp1 = [a * b | a <- [0..99], b <- [0..99], a + b < 15] | |
// [a + b * b | a <- [0..99], b <- comp1, b * b < 20] | |
auto comp1 = comp!(q{a * b}, q{a + b < 15})(iota(100), iota(100)); | |
writeln( | |
array( | |
comp!(q{a + b * b}, q{b * b < 20})(iota(100), comp1) | |
) | |
); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment