mratsim / loop-fusion Goto Github PK
View Code? Open in Web Editor NEWLoop efficiently over a variadic number of containers
License: Other
Loop efficiently over a variadic number of containers
License: Other
There is one big reason why I don't like the forEach
, and that is my Scala background.
val seq1 = Seq(1,2,3)
val seq2 = Seq(4,5,6)
for( a <- seq1, b <- seq2 ) {
println(a,b)
}
val seq1 = Seq(1,2,3)
val seq2 = Seq(4,5,6)
is compiled to:
seq1.forEach(a => seq2.forEach(b => println(a,b))
This is basically just a nested loop with λ-expressions as the body. Zip would be the following:
val seq1 = Seq(1,2,3)
val seq2 = Seq(4,5,6)
for( (a,b) <- zip(seq1, seq2) ) {
println(a,b)
}
I don't say you should take over or try to mimic the Scala syntax, but I think you should take over the names. Please call it to something that has both for and zip in the name. forEach
has already a very specific meaning in my head, and it is not what you are doing with forEach
. Also c++ has already std::foreach
and it means the same as in scala (it's just useless in c++, but that is an opinion and a different topic). And I don't think it is a bad idea to adopt to scala naming conventions (I personally really liked them for the most part)
(please don't kill me if the scala snippents don't compile, I did not program scala for years, and I have no compiler on this machine)
https://github.com/nim-lang/Nim/issues/7996 will introduce the indexable concept.
Loop fusion should work on all indexable containers.
This is blocked by #7737
Loop-fusion code can be greatly simplified using the macro from Laser especially the forEachContiguous macro.
Furthermore they also support parallel processing via OpenMP for non-ref types and types with trivial destructors.
As explained in the readme:
Expressions must return value of the same types, i.e. you can't return void/no value at some iterations and a concrete value at other iterations.
This prevents:
import ../loopfusion
let a = @[1, 2, 3]
let b = @[4, 5, 6]
let c = forZip(x in a, y in b):
if x mod 2 != 0:
y
doAssert c == @[1, 3] # Error: expression 'y' is of type 'int' and has to be discarded
Nim list comprehension can serve as inspiration:
https://github.com/nim-lang/Nim/blob/devel/lib/pure/sugar.nim
type ListComprehension = object
var lc*: ListComprehension
macro `[]`*(lc: ListComprehension, comp, typ: untyped): untyped =
## List comprehension, returns a sequence. `comp` is the actual list
## comprehension, for example ``x | (x <- 1..10, x mod 2 == 0)``. `typ` is
## the type that will be stored inside the result seq.
##
## .. code-block:: nim
##
## echo lc[x | (x <- 1..10, x mod 2 == 0), int]
##
## const n = 20
## echo lc[(x,y,z) | (x <- 1..n, y <- x..n, z <- y..n, x*x + y*y == z*z),
## tuple[a,b,c: int]]
expectLen(comp, 3)
expectKind(comp, nnkInfix)
expectKind(comp[0], nnkIdent)
assert($comp[0].ident == "|")
result = newCall(
newDotExpr(
newIdentNode("result"),
newIdentNode("add")),
comp[1])
for i in countdown(comp[2].len-1, 0):
let x = comp[2][i]
expectMinLen(x, 1)
if x[0].kind == nnkIdent and $x[0].ident == "<-":
expectLen(x, 3)
result = newNimNode(nnkForStmt).add(x[1], x[2], result)
else:
result = newIfStmt((x, result))
result = newNimNode(nnkCall).add(
newNimNode(nnkPar).add(
newNimNode(nnkLambda).add(
newEmptyNode(),
newEmptyNode(),
newEmptyNode(),
newNimNode(nnkFormalParams).add(
newNimNode(nnkBracketExpr).add(
newIdentNode("seq"),
typ)),
newEmptyNode(),
newEmptyNode(),
newStmtList(
newAssignment(
newIdentNode("result"),
newNimNode(nnkPrefix).add(
newIdentNode("@"),
newNimNode(nnkBracket))),
result))))
This assumes that indexing starts at 0: https://github.com/numforge/loop-fusion/blob/1b928f224c2c67fc035544c4d870398afd646022/loopfusion.nim#L167-L180
But array can start at an arbitrary value for example: array['0'..'F', uint8]
for an array of 8-bit registers or for arrays of enum that goes from -10 to 0
by @bluenote10 on the Nim forum:
forEachIndexed j, x in xs, y in ys, z in zs:
...
Excellent proposal, I don't know how but I'll implement it.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.