digitalmars.D - emit: generalizes map, filter, joiner [proposal + implementation]
- Timothee Cour via Digitalmars-d (12/12) Mar 21 2016 given fun(put, a) a lambda that can call $put 0 or more times,
- Seb (3/5) Mar 21 2016 Could you try to point out whats wrong with map & filter?
- Tamas (4/5) Mar 21 2016 It's hard to do stuff like this:
- Nick Treleaven (4/9) Mar 23 2016 Seems doable:
- Tamas (3/13) Mar 23 2016 This one emits only 1 element when a==3. (BTW what is `mapFilter`
- Nick Treleaven (5/20) Mar 24 2016 It combines both functions, the lambda returns an Option type
- thedeemon (9/14) Mar 23 2016 Is it a bug or you forgot 0 here?
- crimaniak (11/16) Mar 23 2016 map: 1 element -> 1 element
- cy (26/27) Mar 25 2016 I wonder if "template emit(alias fun, T)" wouldn't be a better
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
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
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
On Monday, 21 March 2016 at 23:09:27 UTC, Tamas wrote:On Monday, 21 March 2016 at 11:48:52 UTC, Seb wrote:Seems doable: mapFilter!((a){if(a%2) return some(a*a); if(a%3==0) return some(a); return none;})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 23 2016
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:This one emits only 1 element when a==3. (BTW what is `mapFilter` and `some`?)On Monday, 21 March 2016 at 11:48:52 UTC, Seb wrote:Seems doable: mapFilter!((a){if(a%2) return some(a*a); if(a%3==0) return some(a); return none;})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 23 2016
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:Oops, thanks.On Monday, 21 March 2016 at 23:09:27 UTC, Tamas wrote:This one emits only 1 element when a==3.On Monday, 21 March 2016 at 11:48:52 UTC, Seb wrote:Seems doable: mapFilter!((a){if(a%2) return some(a*a); if(a%3==0) return some(a); return none;})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]));(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
On Monday, 21 March 2016 at 23:09:27 UTC, Tamas wrote:On Monday, 21 March 2016 at 11:48:52 UTC, Seb wrote: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.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 23 2016
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:I support idea to have such feature, sometimes it really need.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])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
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