www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Ruby-style "each" in D?

reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Pros and cons are already being discussed. Destroy!

https://github.com/D-Programming-Language/phobos/pull/2024


Andrei
Mar 19 2014
next sibling parent "Meta" <jared771 gmail.com> writes:
On Wednesday, 19 March 2014 at 15:06:40 UTC, Andrei Alexandrescu 
wrote:
 Pros and cons are already being discussed. Destroy!

 https://github.com/D-Programming-Language/phobos/pull/2024


 Andrei
Very similar to one of the additions I proposed awhile ago. The only difference is that my each() didn't call popFront(). http://forum.dlang.org/thread/ovbjcmogezbvsxrwfcol forum.dlang.org#post-mailman.621.1370146215.13711.digitalmars-d:40puremagic.com
Mar 19 2014
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Andrei Alexandrescu:

 Pros and cons are already being discussed. Destroy!

 https://github.com/D-Programming-Language/phobos/pull/2024
I proposed the same function in D.learn, but this discussion needs a list of use cases and usage examples, otherwise you can't decide in vacuum. It's named "foreach" in Scala: http://twitter.github.io/scala_school/collections.html#foreach Elsewhere I suggested a function that could be named tap() that's usable to debug UFCS chains, interspersing it in the chain, to add imperative calls to writeln. You can replace a each() with a tap + some kind of eager consumer. In many cases what I want to put in each() is a writef/writefln, you can do it like this (binaryReverseArgs is in std.functional): foo .bar .spam .binaryReverseArgs!writefln("%(%s-%): %d", 5); With a shorter flipping name it gets better: foo .bar .spam .flipTwoArgs!writefln("%(%s-%): %d", 5); or even (http://zvon.org/other/haskell/Outputprelude/flip_f.html ) (flips only the first two args and doesn't flip the successive ones): foo .bar .spam .flip!writefln("%(%s-%): %d", 5); Let's say in each() you want to do something different, like incrementing a variable: foo .bar .spam .each!(n => x += n); Is this good enough? If you want to double the contents of an array: myArray.each((ref x) => x * 2); But in D you can also use: myArray[] *= 2; I guess you can't use each() on opApply-based iterables, while you can with foreach(). This makes each() less useful. Is the following code supported? And what is each() receiving from the associative array? int[string] aa; aa.each(...); Perhaps you must use: int[string] aa; aa.byKey.each(...); aa.byValue.each(...); aa.byPair.each(...); While arrays should be OK, but there is no index support: int[] arr; arr.each(...); If you need dynamic array index support: int[] arr; arr.enumerate.each(...); Is this supported? int[10] arr2; arr2.each(...); Or do you have to use this? int[10] arr2; arr2[].each(...); Bye, bearophile
Mar 19 2014
prev sibling next sibling parent reply "Dicebot" <public dicebot.lv> writes:
I would have supported if it was lazy. Not in its proposed form.
Mar 19 2014
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 3/19/14, 8:55 AM, Dicebot wrote:
 I would have supported if it was lazy. Not in its proposed form.
Good point. Maybe forall would be a better name. Andrei
Mar 19 2014
next sibling parent reply "Dicebot" <public dicebot.lv> writes:
On Wednesday, 19 March 2014 at 16:01:06 UTC, Andrei Alexandrescu 
wrote:
 On 3/19/14, 8:55 AM, Dicebot wrote:
 I would have supported if it was lazy. Not in its proposed 
 form.
Good point. Maybe forall would be a better name. Andrei
I think "each" is a good name but it should instead return range that calls predicate function upon "popFront" and proxies input argument further from "front". bearophile has been proposing it under name "tap", but I like "each" more.
Mar 19 2014
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 3/19/14, 9:03 AM, Dicebot wrote:
 On Wednesday, 19 March 2014 at 16:01:06 UTC, Andrei Alexandrescu wrote:
 On 3/19/14, 8:55 AM, Dicebot wrote:
 I would have supported if it was lazy. Not in its proposed form.
Good point. Maybe forall would be a better name. Andrei
I think "each" is a good name but it should instead return range that calls predicate function upon "popFront" and proxies input argument further from "front". bearophile has been proposing it under name "tap", but I like "each" more.
tee is already being discussed -- Andrei
Mar 19 2014
parent reply "Dicebot" <public dicebot.lv> writes:
On Wednesday, 19 March 2014 at 16:04:16 UTC, Andrei Alexandrescu 
wrote:
 tee is already being discussed -- Andrei
On this topic, do we have something like "consume" in Phobos to eagerly iterate through the supplied range? Don't see anything similar at first glance and it will be needed to express same idiom via "tap"/"tee" in a readable form.
Mar 19 2014
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 3/19/14, 9:09 AM, Dicebot wrote:
 On Wednesday, 19 March 2014 at 16:04:16 UTC, Andrei Alexandrescu wrote:
 tee is already being discussed -- Andrei
On this topic, do we have something like "consume" in Phobos to eagerly iterate through the supplied range?
A default "each" would do that. Andrei
Mar 19 2014
parent reply "Dicebot" <public dicebot.lv> writes:
On Wednesday, 19 March 2014 at 16:40:24 UTC, Andrei Alexandrescu 
wrote:
 On 3/19/14, 9:09 AM, Dicebot wrote:
 On Wednesday, 19 March 2014 at 16:04:16 UTC, Andrei 
 Alexandrescu wrote:
 tee is already being discussed -- Andrei
On this topic, do we have something like "consume" in Phobos to eagerly iterate through the supplied range?
A default "each" would do that. Andrei
No, I don't mean iterate with predicate. I mean /dev/null thing. My point is that `range.each!predicate` is much better replaced with `range.tap!predicate.consume`. It keeps general rule of range stuff being lazy and only single exception to bail out of it has very readable clear name. One can argue that "consume" is same as proposed "each" with no-op predicate but I think it is very important for readability to keep exceptional behavior (eager consumption) separated from utility behavior (tapping with a predicate).
Mar 19 2014
next sibling parent "Meta" <jared771 gmail.com> writes:
On Wednesday, 19 March 2014 at 16:46:41 UTC, Dicebot wrote:
 No, I don't mean iterate with predicate. I mean /dev/null thing.

 My point is that `range.each!predicate` is much better replaced 
 with `range.tap!predicate.consume`. It keeps general rule of 
 range stuff being lazy and only single exception to bail out of 
 it has very readable clear name.

 One can argue that "consume" is same as proposed "each" with 
 no-op predicate but I think it is very important for 
 readability to keep exceptional behavior (eager consumption) 
 separated from utility behavior (tapping with a predicate).
I also proposed this in the thread I linked, but it was also rejected. I remember Andrei saying that "consume" should really just be reduce called with no predicate, but I think that wouldn't work for some reason...
Mar 19 2014
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 3/19/14, 9:46 AM, Dicebot wrote:
 On Wednesday, 19 March 2014 at 16:40:24 UTC, Andrei Alexandrescu wrote:
 On 3/19/14, 9:09 AM, Dicebot wrote:
 On Wednesday, 19 March 2014 at 16:04:16 UTC, Andrei Alexandrescu wrote:
 tee is already being discussed -- Andrei
On this topic, do we have something like "consume" in Phobos to eagerly iterate through the supplied range?
A default "each" would do that. Andrei
No, I don't mean iterate with predicate. I mean /dev/null thing.
So did I - "each" could take a default alias. -- Andrei
Mar 19 2014
parent "Dicebot" <public dicebot.lv> writes:
On Wednesday, 19 March 2014 at 17:39:16 UTC, Andrei Alexandrescu 
wrote:
 So did I - "each" could take a default alias. -- Andrei
We could have saved some time if you have replied directly to my objection to your objection I have foreseen :P (see last part of the comment)
Mar 19 2014
prev sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Wednesday, 19 March 2014 at 16:46:41 UTC, Dicebot wrote:
 My point is that `range.each!predicate` is much better replaced 
 with `range.tap!predicate.consume`. It keeps general rule of 
 range stuff being lazy and only single exception to bail out of 
 it has very readable clear name.

 One can argue that "consume" is same as proposed "each" with 
 no-op predicate but I think it is very important for 
 readability to keep exceptional behavior (eager consumption) 
 separated from utility behavior (tapping with a predicate).
This. I fully agree.
Mar 19 2014
prev sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Wednesday, 19 March 2014 at 16:09:31 UTC, Dicebot wrote:
 On Wednesday, 19 March 2014 at 16:04:16 UTC, Andrei 
 Alexandrescu wrote:
 tee is already being discussed -- Andrei
On this topic, do we have something like "consume" in Phobos to eagerly iterate through the supplied range?
I had proposed "walk", which would be consistent with the already existing "walkLength". An "each()" with no arg could also do the trick, but that would also call the "front", which means it's not the exact same behavior (not better or worst, just different).
Mar 19 2014
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 03/19/2014 05:01 PM, Andrei Alexandrescu wrote:
 On 3/19/14, 8:55 AM, Dicebot wrote:
 I would have supported if it was lazy. Not in its proposed form.
Good point. Maybe forall would be a better name. Andrei
http://en.wikipedia.org/wiki/Forall
Mar 19 2014
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 3/19/14, 9:10 AM, Timon Gehr wrote:
 On 03/19/2014 05:01 PM, Andrei Alexandrescu wrote:
 On 3/19/14, 8:55 AM, Dicebot wrote:
 I would have supported if it was lazy. Not in its proposed form.
Good point. Maybe forall would be a better name. Andrei
http://en.wikipedia.org/wiki/Forall
Never mind, each is better :o) -- Andrei
Mar 19 2014
prev sibling next sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Wednesday, 19 March 2014 at 15:55:14 UTC, Dicebot wrote:
 I would have supported if it was lazy. Not in its proposed form.
How would it work in lazy form? Or do you mean the "tee" we are talking about in the discussion? The fact that it *isn't* lazy is part of the design (AFAIK). I can't see it work without it.
Mar 19 2014
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 3/19/2014 8:55 AM, Dicebot wrote:
 I would have supported if it was lazy. Not in its proposed form.
Also if it is implicitly parallelizable or not, i.e. are there traversal order dependencies?
Mar 19 2014
prev sibling next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 3/19/2014 8:06 AM, Andrei Alexandrescu wrote:
 Pros and cons are already being discussed. Destroy!
I don't have a solid enough experience with this style of programming, but one opportunity of 'each' could be that it could be specialized and achieve greater speed for some arguments.
Mar 19 2014
parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Wednesday, 19 March 2014 at 23:00:08 UTC, Walter Bright wrote:
 I don't have a solid enough experience with this style of 
 programming, but one opportunity of 'each' could be that it 
 could be specialized and achieve greater speed for some 
 arguments.
Speaking of which, it would be nice to have a compiler default iteration scheme that is optimal for any range. The current status is: "for ( ; !r.empty ; r.popFront )" is sub-optimal for string types, and sometimes arrays. alias E = ElementEncodingType!Range; "foreach(E e; range);" will create copies of elements "foreach(ref E e; range);" will always work, but is arguably wrong for RValue ranges "foreach(auto ref E e; range);" is not legal, but there is an ER requesting it, and I think it would make perfect sense to have this. Finally: The hand written library code while ( decode(s, i) < s.length ) { ... } Is faster for strings, than the compiler's/druntime's "foreach(E e; range);". It would be awesome if: foreach(auto ref E e; range); Worked, *and* was always optimal. The current scheme makes those who care jump through hoops, such as in `find`'s implementation.
Mar 19 2014
prev sibling next sibling parent reply "w0rp" <devw0rp gmail.com> writes:
'each' sounds like a good idea for supporting component 
programming a little more. As bearophile as already stated, you 
can do something like this...

someRange.filter!foo.frobulate.each!doSomethingWithIt;

For Walter's question about parallel execution, I imagine 
something like this.

// std.parallelism parallel function here.
someRange.whatever.parallel(numberOfUnits).each!doSomething

Basically it just removes a little foreach boilerplate. I don't 
think the implementation needs to be much more complicated than 
what Andrei wrote already, I would just pull that pretty much 
as-is.

I also don't think an argument like "you can already do this with 
foreach" is valid. You don't *have* to use it, and some people 
might like it. I know I would appreciate having it in 
std.algorithm. (I'm kind of a range fanboy.)
Mar 20 2014
parent reply "Andrea Fontana" <nospam example.com> writes:
On Thursday, 20 March 2014 at 12:32:49 UTC, w0rp wrote:
 // std.parallelism parallel function here.
 someRange.whatever.parallel(numberOfUnits).each!doSomething
+1 This works: foreach(i; [0,1,2,3,4,5].parallel) i.writeln; This works: [0,1,2,3,4,5].each!writeln; This won't compile: [0,1,2,3,4,5].parallel.each!writeln; Error: template tmp.each cannot deduce function from argument types !(writeln)(ParallelForeach!(int[])), candidates are: /tmp/tmp.d(9): tmp.each(alias fun, Range)(Range range) if (isInputRange!Range)
Mar 20 2014
parent reply =?UTF-8?B?U2ltZW4gS2rDpnLDpXM=?= <simen.kjaras gmail.com> writes:
On 2014-03-20 14:16, Andrea Fontana wrote:
 On Thursday, 20 March 2014 at 12:32:49 UTC, w0rp wrote:
 // std.parallelism parallel function here.
 someRange.whatever.parallel(numberOfUnits).each!doSomething
+1 This works: foreach(i; [0,1,2,3,4,5].parallel) i.writeln; This works: [0,1,2,3,4,5].each!writeln; This won't compile: [0,1,2,3,4,5].parallel.each!writeln; Error: template tmp.each cannot deduce function from argument types !(writeln)(ParallelForeach!(int[])), candidates are: /tmp/tmp.d(9): tmp.each(alias fun, Range)(Range range) if (isInputRange!Range)
It could be made to work, though: template isIterable(T) { enum isIterable = is(typeof((T t){foreach (e; t){}})); } template isRefIterable(T) { enum isRefIterable = is(typeof((T t){foreach (ref e; t){}})); } void each(alias fun, Range)(Range range) if (isInputRange!Range) { while (!range.empty) { unaryFun!fun(range.front); range.popFront(); } } void each(alias fun, Range)(Range range) if (!isInputRange!Range && isRefIterable!Range) { foreach (ref e; range) { unaryFun!fun(e); } } void each(alias fun, Range)(Range range) if (!isInputRange!Range && isIterable!Range && !isRefIterable!Range) { foreach (e; range) { unaryFun!fun(e); } } void main() { [0,1,2,3,4,5].parallel.each!writeln; } -- Simen
Mar 20 2014
parent reply "Andrea Fontana" <nospam example.com> writes:
On Thursday, 20 March 2014 at 15:02:46 UTC, Simen Kjærås wrote:
 On 2014-03-20 14:16, Andrea Fontana wrote:
 On Thursday, 20 March 2014 at 12:32:49 UTC, w0rp wrote:
 // std.parallelism parallel function here.
 someRange.whatever.parallel(numberOfUnits).each!doSomething
+1 This works: foreach(i; [0,1,2,3,4,5].parallel) i.writeln; This works: [0,1,2,3,4,5].each!writeln; This won't compile: [0,1,2,3,4,5].parallel.each!writeln; Error: template tmp.each cannot deduce function from argument types !(writeln)(ParallelForeach!(int[])), candidates are: /tmp/tmp.d(9): tmp.each(alias fun, Range)(Range range) if (isInputRange!Range)
It could be made to work, though: template isIterable(T) { enum isIterable = is(typeof((T t){foreach (e; t){}})); } template isRefIterable(T) { enum isRefIterable = is(typeof((T t){foreach (ref e; t){}})); } void each(alias fun, Range)(Range range) if (isInputRange!Range) { while (!range.empty) { unaryFun!fun(range.front); range.popFront(); } } void each(alias fun, Range)(Range range) if (!isInputRange!Range && isRefIterable!Range) { foreach (ref e; range) { unaryFun!fun(e); } } void each(alias fun, Range)(Range range) if (!isInputRange!Range && isIterable!Range && !isRefIterable!Range) { foreach (e; range) { unaryFun!fun(e); } } void main() { [0,1,2,3,4,5].parallel.each!writeln; } -- Simen
I think that pull request should be updated. Why isn't ParallelForEach implemented as Range, instead?
Mar 20 2014
parent "Vladimir Panteleev" <vladimir thecybershadow.net> writes:
On Thursday, 20 March 2014 at 15:25:47 UTC, Andrea Fontana wrote:
 Why isn't ParallelForEach implemented as Range, instead?
Because it can't be. It's not possible to present something as a range, so that that range's consumers would process that range in parallel. std.parallelism.parallel instead (ab)uses the opApply implementation mechanics to execute the foreach body in different threads.
Mar 23 2014
prev sibling parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
On Wednesday, 19 March 2014 at 15:06:40 UTC, Andrei Alexandrescu 
wrote:
 Pros and cons are already being discussed. Destroy!

 https://github.com/D-Programming-Language/phobos/pull/2024


 Andrei
User Ali Çehreli has posted in learn what I think is an interesting problem: http://forum.dlang.org/thread/lgfmbf$v7c$1 digitalmars.com //---- This is a somewhat common little exercise: Write a function that takes the size of a diamond and produces a diamond of that size. When printed, here is the output for size 11: * *** ***** ******* ********* *********** ********* ******* ***** *** * What interesting, boring, efficient, slow, etc. ways are there? Ali //---- The reason I bring it up is that this usually leads to a competition of whoever thinks up the most creative/concise UFCS chain. So here's what I'm thinking: Let's do this, but also using each/tee/tap/consume/walk (and others?)! I think this "real world" scenario is a good bench for seeing the effects of mixing imperative-style statements into a functional-style wrapper. Maybe the result will reveal that something is awesome, or that it is useless? That maybe something that looks like it works, is actually subtly buggy? That maybe each turns out to be useful past our wildest dreams? Who knows?
Mar 20 2014
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
monarch_dodra:

I have just given some solutions in D.learn.


 So here's what I'm thinking: Let's do this, but also using 
 each/tee/tap/consume/walk (and others?)!

 I think this "real world" scenario is a good bench for seeing 
 the effects of mixing imperative-style statements into a 
 functional-style wrapper.
As I explained in a precedent post in this thread it's hard to design something if you don't try to use it, even something simple as a each(). So I approve such exercises. Bye, bearophile
Mar 20 2014
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 3/20/2014 5:33 PM, bearophile wrote:
 As I explained in a precedent post in this thread it's hard to design something
 if you don't try to use it, even something simple as a each().
Right on.
Mar 20 2014
next sibling parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
On Friday, 21 March 2014 at 00:42:00 UTC, Walter Bright wrote:
 On 3/20/2014 5:33 PM, bearophile wrote:
 As I explained in a precedent post in this thread it's hard to 
 design something
 if you don't try to use it, even something simple as a each().
Right on.
So I toyed around a little. I played with mostly tee/tap and each. The first observation is that both can help make a "2D" ufcs chain, which is pretty nice. It makes more sense (IMO) to code it that way, than to use awkward "join", to concatenate the "2D" range into a continuous "1D" range, eg: join(lines, "\n"); First: "tee". I wanted to try to experience the "multiple tees" approach. I made the code purposefully verbose, so as to better test it. Because I wanted to process each item once, and only once, I used the default policy of `Yes.pipeOnPop`. I did some tests with both "tee!pred" and "tee(range, output)", but they were functionally equivalent. Anyways, here was my first iteration: //---- size_t N = 5; chain(iota(0, N), only(N), iota(0, N).retro) //0 .. N .. 0 .tee!((a)=>' '.repeat(N - a).write())() //leading spaces .tee!((a)=>'*'.repeat(a).write())() //first half of stars .tee!((a)=>'*'.write())() //middle star .tee!((a)=>'*'.repeat(a).write())() //second half .tee!((a)=>writeln())() //linefeed .reduce!"0"(0); //or consume/walk //---- Surprise! It's wrong! each "tee" triggers on the call to `popFront`. It does its job (calls pred(r.front)), and then push the "pop down the chain. What this means is that my "tee's" are actually executed right to left! Talk about counter intuitive. So *this* is correct: //---- size_t N = 5; chain(iota(0, N), only(N), iota(0, N).retro) //0 .. N .. 0 .tee!((a)=>writeln())() //linefeed .tee!((a)=>'*'.repeat(a).write())() //second half .tee!((a)=>'*'.write())() //middle star .tee!((a)=>'*'.repeat(a).write())() //first half of stars .tee!((a)=>' '.repeat(N - a).write())() //leading spaces .reduce!"0"(0); //or consume/walk/each() //---- Odd! Second: Each tee pipes a call to front, and *then* calls front again when popped. Effectively, if you have *N* tee's in your range, you'll call "fun" roughly N*N/2 times. Not great. This might be an unfair assesment of "tee", because I over-used it on purpose, but I think it *does* show that it's not scaling well, and that it is triggering in a confusing order. Also: //---- size_t N = 5; foreach ( a ; chain(iota(0, N), only(N), iota(0, N).retro)) { ' '.repeat(N - a).write(); '*'.repeat(a).write(); '*'.write(); '*'.repeat(a).write(); writeln(); } //---- Just saying. Why would I use "tee" when I have that? But I think I'm using "tee" wrong: The idea is to "hook" it into a chain that actually does something. It shouldn't be the main "doer". --------------------------------------------- What about each? I wrote this: //---- chain(iota(0, N), only(N), iota(0, N).retro) .each!( (a) => writeln(' '.repeat(N - a), '*'.repeat(a*2+1)) )(); //---- I think this is a fair assesment of how "each" would be used? It looks nice, and is relatively short. But then I wrote this: //---- foreach ( a ; chain(iota(0, N), only(N), iota(0, N).retro) ) { writeln(' '.repeat(N - a), '*'.repeat(a*2+1))) } //---- Hum... you still get the same functional initial declaration, but the "foreach" doesn't get in the way, while still keeping a clear functional/imperative distinction. ------------------------------------------ Si that's my initial assessment. I'm not really sold on "each". I think it'll be abused by those that want a "1-liner" at all cost, leading to an image that "D is nothing but horrible 1 liners!", all that without providing any real functionality. As for "tee": I'm convinced I didn't use it for its intended function, but I think it shows its function can easily be hijacked to do things it wasn't meant for.
Mar 21 2014
next sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
monarch_dodra:

 chain(iota(0, N), only(N), iota(0, N).retro)
     .each!(
         (a) => writeln(' '.repeat(N - a), '*'.repeat(a*2+1))
     )();
 //----
Something like this seems better (untested): chain(N.iota, N.only, N.iota.retro) .each!(a => '*'.replicate(a * 2 + 1).center(N).writeln);
 I think this is a fair assesment of how "each" would be used?
This UFCS chain is just 2 lines long, it's not the best usage example of each().
 I'm not really sold on "each".
 ...
 As for "tee": I'm convinced I didn't use it for its intended 
 function, but I think it shows its function can easily be 
 hijacked to do things it wasn't meant for.
You have used tee for something you think it's not very well designed, and you have given only one usage example of each(), and it's not the most common example. So before taking any decision on the matter, more experiments and usage examples are necessary, where you have longer chains. If you have a longer chain: items .sort() .group .map!(g => g[1] / double(s.length)) .map!(p => -p * p.log2) .sum .each(...); using a each() allows you to keep a nice column. If you use foreach your formatting and your logic has a hiccup, because you are mixing two different styles: foreach (item; items .sort() .group .map!(g => g[1] / double(s.length)) .map!(p => -p * p.log2) .sum) { // Do something imperative here. } But this is not a real example (it computes the entropy of items, and you usually don't need an each there), so more usage examples are needed. Taking a look at real world usages of foreach() in Scala could be useful.
 I think it'll be abused by those that want a "1-liner" at all 
 cost, leading to an image that "D is nothing but horrible 1 
 liners!", all that without providing any real functionality.
languages. Some possible usage examples for each(): import std.stdio, std.algorithm, std.string, std.exception, std.file; void main() { string[][ubyte[]] an; foreach (w; "unixdict.txt".readText.splitLines) an[w.dup.representation.sort().release.assumeUnique] ~= w; immutable m = an.byValue.map!q{ a.length }.reduce!max; writefln("%(%s\n%)", an.byValue.filter!(ws => ws.length == m)); } auto mode(T)(T[] items) pure nothrow { int[T] aa; foreach (item; items) aa[item]++; immutable m = aa.byValue.reduce!max; return aa.byKey.filter!(k => aa[k] == m); } double equalBirthdays(in uint nSharers, in uint groupSize, in uint nRepetitions, ref Xorshift rng) { uint eq = 0; foreach (immutable j; 0 .. nRepetitions) { uint[365] group; foreach (immutable i; 0 .. groupSize) group[uniform(0, $, rng)]++; eq += group[].any!(c => c >= nSharers); } return (eq * 100.0) / nRepetitions; } Bye, bearophile
Mar 21 2014
parent "Jakob Ovrum" <jakobovrum gmail.com> writes:
On Friday, 21 March 2014 at 12:29:31 UTC, bearophile wrote:
 So before taking any decision on the matter, more experiments 
 and usage examples are necessary, where you have longer chains. 
 If you have a longer chain:

 items
 .sort()
 .group
 .map!(g => g[1] / double(s.length))
 .map!(p => -p * p.log2)
 .sum
 .each(...);

 using a each() allows you to keep a nice column. If you use 
 foreach your formatting and your logic has a hiccup, because 
 you are mixing two different styles:

 foreach (item; items
                .sort()
                .group
                .map!(g => g[1] / double(s.length))
                .map!(p => -p * p.log2)
                .sum) {
     // Do something imperative here.
 }

 But this is not a real example (it computes the entropy of 
 items, and you usually don't need an each there), so more usage 
 examples are needed. Taking a look at real world usages of 
 foreach() in Scala could be useful.
The former example doesn't become functional just because you managed to use UFCS, it's just imperative code deceptively disguised as functional code. The clear separation in the latter example is a *good thing*.
Mar 21 2014
prev sibling next sibling parent reply "Jacob Carlborg" <doob me.com> writes:
On Friday, 21 March 2014 at 11:03:01 UTC, monarch_dodra wrote:

 each "tee" triggers on the call to `popFront`. It does its job 
 (calls pred(r.front)), and then push the "pop down the chain. 
 What this means is that my "tee's" are actually executed right 
 to left! Talk about counter intuitive.
What's the purpose of "tee", is it the same as "tap"? "tap" in Ruby just returns the receiver after executing a block. This would be the implementation in D: T tap (alias block, T) (T t) { block(t); return t; } -- /Jacob Carlborg
Mar 21 2014
parent reply "Dicebot" <public dicebot.lv> writes:
On Friday, 21 March 2014 at 12:55:09 UTC, Jacob Carlborg wrote:
 What's the purpose of "tee", is it the same as "tap"? "tap" in 
 Ruby just returns the receiver after executing a block. This 
 would be the implementation in D:
Yeah "tee" is a horrible name, no chance I would have guess what it means just by the name. "tap" is much better.
Mar 21 2014
parent reply "Vladimir Panteleev" <vladimir thecybershadow.net> writes:
On Friday, 21 March 2014 at 13:24:50 UTC, Dicebot wrote:
 On Friday, 21 March 2014 at 12:55:09 UTC, Jacob Carlborg wrote:
 What's the purpose of "tee", is it the same as "tap"? "tap" in 
 Ruby just returns the receiver after executing a block. This 
 would be the implementation in D:
Yeah "tee" is a horrible name, no chance I would have guess what it means just by the name. "tap" is much better.
I think it's meant to mimic the UNIX command with the same name? If you know about the command, the function's purpose seems obvious.
Mar 21 2014
next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Vladimir Panteleev:

 Dicebot:
 Yeah "tee" is a horrible name, no chance I would have guess 
 what it means just by the name. "tap" is much better.
I think it's meant to mimic the UNIX command with the same name? If you know about the command, the function's purpose seems obvious.
See also the Python function tee(): http://docs.python.org/2/library/itertools.html#itertools.tee Bye, bearophile
Mar 21 2014
prev sibling parent reply "Dicebot" <public dicebot.lv> writes:
On Friday, 21 March 2014 at 13:27:04 UTC, Vladimir Panteleev 
wrote:
 On Friday, 21 March 2014 at 13:24:50 UTC, Dicebot wrote:
 On Friday, 21 March 2014 at 12:55:09 UTC, Jacob Carlborg wrote:
 What's the purpose of "tee", is it the same as "tap"? "tap" 
 in Ruby just returns the receiver after executing a block. 
 This would be the implementation in D:
Yeah "tee" is a horrible name, no chance I would have guess what it means just by the name. "tap" is much better.
I think it's meant to mimic the UNIX command with the same name? If you know about the command, the function's purpose seems obvious.
...and has pretty much nothing in common with it! Also I don't see "requires UNIX familiarity to be used intuitively" warning in Phobos docs. Actually for similar reasons "tap" is also inferior to "each".
Mar 21 2014
parent "Vladimir Panteleev" <vladimir thecybershadow.net> writes:
On Friday, 21 March 2014 at 13:33:21 UTC, Dicebot wrote:
 On Friday, 21 March 2014 at 13:27:04 UTC, Vladimir Panteleev 
 wrote:
 On Friday, 21 March 2014 at 13:24:50 UTC, Dicebot wrote:
 On Friday, 21 March 2014 at 12:55:09 UTC, Jacob Carlborg 
 wrote:
 What's the purpose of "tee", is it the same as "tap"? "tap" 
 in Ruby just returns the receiver after executing a block. 
 This would be the implementation in D:
Yeah "tee" is a horrible name, no chance I would have guess what it means just by the name. "tap" is much better.
I think it's meant to mimic the UNIX command with the same name? If you know about the command, the function's purpose seems obvious.
...and has pretty much nothing in common with it!
Why do you think so? range .filter!(s => s.canFind("foo")) .tee!writeln ... is equivalent to cat input \ | grep foo \ | tee /dev/pts/N \ | ...
Mar 23 2014
prev sibling next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 3/21/14, 4:02 AM, monarch_dodra wrote:
 So I toyed around a little. I played with mostly tee/tap and each. The
 first observation is that both can help make a "2D" ufcs chain, which is
 pretty nice. It makes more sense (IMO) to code it that way, than to use
 awkward "join", to concatenate the "2D" range into a continuous "1D"
 range, eg: join(lines, "\n");

 First: "tee".
Nice work! This convinced me that tee should call the lambda only upon the first call to .front on each iteration. Andrei
Mar 21 2014
prev sibling parent "w0rp" <devw0rp gmail.com> writes:
On Friday, 21 March 2014 at 11:03:01 UTC, monarch_dodra wrote:
 //----
 foreach ( a ;
     chain(iota(0, N), only(N), iota(0, N).retro) )
 {
     writeln(' '.repeat(N - a), '*'.repeat(a*2+1)))
 }
 //----
I don't think it's so complicated. It's just taking this. someRange.mungeItHowever.each!useIt; Instead of writing this. foreach(someThing; someRange.mungeItHowever) someThing.useIt; Maybe it's like the difference between writing foo(bar) and bar.foo. It can just look a little nicer.
Mar 21 2014
prev sibling parent "Jacob Carlborg" <doob me.com> writes:
On Friday, 21 March 2014 at 00:42:00 UTC, Walter Bright wrote:

 Right on.
I'm using Ruby every day. I don't really see much point in having "each" in D. We already have "foreach". Ruby uses "each" since it doesn't have "foreach". It to have a "for", which is a form of foreach, but that is just lowered to "each" anyway. Also, I don't see a point in having "each" which is lazy. -- /Jacob Carlborg
Mar 21 2014