Skip to content

Instantly share code, notes, and snippets.

@MartinNowak
Created September 1, 2011 19:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MartinNowak/1186982 to your computer and use it in GitHub Desktop.
Save MartinNowak/1186982 to your computer and use it in GitHub Desktop.
Range interface List comprehension
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