Ruby-style "each" in D?

bearophile bearophileHUGS at lycos.com
Fri Mar 21 05:29:29 PDT 2014


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.

I think each() is meant for longer chains as you see in F# 
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


More information about the Digitalmars-d mailing list