www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - emit: generalizes map, filter, joiner [proposal + implementation]

reply Timothee Cour via Digitalmars-d <digitalmars-d puremagic.com> writes:
given fun(put, a) a lambda that can call $put 0 or more times,
some_range.emit!fun computes a range formed of all the calls to $put

eg:
assert(9.iota.emit!(int,(put,a){if(a%2) put(a*a);}).equal([1, 9, 25, 49]));

in this case it can be done by combining map and filter but in other cases
emit is more powerful and an equivalent (with map,filter,joiner) can be
inefficient and more complex.

see https://github.com/timotheecour/dtools/blob/master/dtools/util/emit.d

could that be turned into std.algorithm.iteration.emit (after addressing
comments) ?

Any comments would be appreciated (especially regarding whether we can get
rid of the 1st template argument with type deduction)
Mar 21 2016
next sibling parent reply Seb <seb wilzba.ch> writes:
On Monday, 21 March 2016 at 11:35:49 UTC, Timothee Cour wrote:
 assert(9.iota.emit!(int,(put,a){if(a%2) put(a*a);}).equal([1, 
 9, 25, 49]))
Could you try to point out whats wrong with map & filter? assert(9.iota.filter!"a%2".map!"a*a".equal([1, 9, 25, 49])
Mar 21 2016
next sibling parent reply Tamas <user dlang.io> writes:
On Monday, 21 March 2016 at 11:48:52 UTC, Seb wrote:
 Could you try to point out whats wrong with map & filter?
It's hard to do stuff like this: assert(9.iota.emit!(int,(put,a){if(a%2) put(a*a); if(a%3==0) put(a);}).equal([1,9,3,25,6,49]));
Mar 21 2016
next sibling parent reply Nick Treleaven <ntrel-pub mybtinternet.com> writes:
On Monday, 21 March 2016 at 23:09:27 UTC, Tamas wrote:
 On Monday, 21 March 2016 at 11:48:52 UTC, Seb wrote:
 Could you try to point out whats wrong with map & filter?
It's hard to do stuff like this: assert(9.iota.emit!(int,(put,a){if(a%2) put(a*a); if(a%3==0) put(a);}).equal([1,9,3,25,6,49]));
Seems doable: mapFilter!((a){if(a%2) return some(a*a); if(a%3==0) return some(a); return none;})
Mar 23 2016
parent reply Tamas <user dlang.io> writes:
On Wednesday, 23 March 2016 at 17:29:55 UTC, Nick Treleaven wrote:
 On Monday, 21 March 2016 at 23:09:27 UTC, Tamas wrote:
 On Monday, 21 March 2016 at 11:48:52 UTC, Seb wrote:
 Could you try to point out whats wrong with map & filter?
It's hard to do stuff like this: assert(9.iota.emit!(int,(put,a){if(a%2) put(a*a); if(a%3==0) put(a);}).equal([1,9,3,25,6,49]));
Seems doable: mapFilter!((a){if(a%2) return some(a*a); if(a%3==0) return some(a); return none;})
This one emits only 1 element when a==3. (BTW what is `mapFilter` and `some`?)
Mar 23 2016
parent Nick Treleaven <ntrel-pub mybtinternet.com> writes:
On Wednesday, 23 March 2016 at 17:43:07 UTC, Tamas wrote:
 On Wednesday, 23 March 2016 at 17:29:55 UTC, Nick Treleaven 
 wrote:
 On Monday, 21 March 2016 at 23:09:27 UTC, Tamas wrote:
 On Monday, 21 March 2016 at 11:48:52 UTC, Seb wrote:
 Could you try to point out whats wrong with map & filter?
It's hard to do stuff like this: assert(9.iota.emit!(int,(put,a){if(a%2) put(a*a); if(a%3==0) put(a);}).equal([1,9,3,25,6,49]));
Seems doable: mapFilter!((a){if(a%2) return some(a*a); if(a%3==0) return some(a); return none;})
This one emits only 1 element when a==3.
Oops, thanks.
 (BTW what is `mapFilter` and `some`?)
It combines both functions, the lambda returns an Option type representing 0 or 1 element: http://forum.dlang.org/post/ncom7m$1ebr$1 digitalmars.com
Mar 24 2016
prev sibling parent thedeemon <dlang thedeemon.com> writes:
On Monday, 21 March 2016 at 23:09:27 UTC, Tamas wrote:
 On Monday, 21 March 2016 at 11:48:52 UTC, Seb wrote:
 Could you try to point out whats wrong with map & filter?
It's hard to do stuff like this: assert(9.iota.emit!(int,(put,a){if(a%2) put(a*a); if(a%3==0) put(a);}).equal([1,9,3,25,6,49]));
Is it a bug or you forgot 0 here? How it looks with Phobos today: auto r = new Generator!int({ 9.iota.each!((a) { if (a % 2) yield(a*a); if (a % 3 == 0) yield(a); }); }); assert(r.equal([0,1,9,3,25,6,49])); Probably much less efficient, of course.
Mar 23 2016
prev sibling parent crimaniak <crimaniak gmail.com> writes:
On Monday, 21 March 2016 at 11:48:52 UTC, Seb wrote:
 On Monday, 21 March 2016 at 11:35:49 UTC, Timothee Cour wrote:
 assert(9.iota.emit!(int,(put,a){if(a%2) put(a*a);}).equal([1, 
 9, 25, 49]))
I support idea to have such feature, sometimes it really need.
 Could you try to point out whats wrong with map & filter?

 assert(9.iota.filter!"a%2".map!"a*a".equal([1, 9, 25, 49])
map: 1 element -> 1 element filter: 1 element -> 0..1 element(s) emit: 1 element -> 0..infinite elements This feature is more generic then map() and filter() together. But proposed implementation is not good. I think this is good place for generator function with yield. If map() will accept generators and process it as expected, different from ordinary functions, then additional emit() method is not needed. And filter() too :)
Mar 23 2016
prev sibling parent cy <dlang verge.info.tm> writes:
 template emit(T, alias fun)
I wonder if "template emit(alias fun, T)" wouldn't be a better idea. That way you could leave T open for type inference, even if you specify a function. D doesn't support reordering template arguments, so it's important to put the ones "most used" at the beginning. Anyway, it looks neat. I hope you've looked at std.algorithm.iteration.reduce though? It does the same thing that emit does, and it's an ancient algorithm. "fold" is just reduce with the arguments more convenient for D's syntax. But... assert(9.iota.emit!(int,(put,a){if(a%2) put(a*a);}).equal([1, 9, 25, 49])); => int[] intderp; assert(9.iota.fold!((result,a) { if(a%2) return result ~ [a*a]; else return result;})(intderp) == ([1,9,25,49])); What would be neat is a "reduce" that could produce an infinite range as a result. All I can do with reduce and fold is produce an eagerly evaluated growing array in memory, or something like chain(chain(chain(chain(chain(...))))) which uses up memory just from creating all those iterators. Like, I don't know how to use fold! to do this: auto natural_numbers = sequence!"n"(); auto oddsquared = natural_numbers.filter!"a%2==1".map!"a*a"; // fold? assert(take(oddsquared,4).equal([1, 9, 25, 49]));
Mar 25 2016