Range of n lines from stdin

Ivan Kazmenko gassa at mail.ru
Sat Dec 28 03:50:03 PST 2013


Many thanks to Marco, Ali and Jakob for the answers!

On Saturday, 28 December 2013 at 08:56:53 UTC, Jakob Ovrum wrote:
> On Friday, 27 December 2013 at 20:30:52 UTC, Ivan Kazmenko 
> wrote:
>> Hmm?..  From my experience, attempting to use a range in a 
>> wrong way usually results in a compilation error.  For 
>> example, I can't do
>> n.iota.map!(_ => readln).sort())
>> since MapResult isn't a random access range with swappable 
>> elements. I can instead do
>> n.iota.map!(_ => readln).array().sort())
>> and it allocates an array and works as expected.  So, how do I 
>> misuse that range?
>
> Yes, the idea is that ranges only present interfaces that make 
> sense, so cases of misuse will result in a compilation error. 
> However, hacks like using map with functions that ignore their 
> argument(s) throws that out of the window: `r` in `auto r = 
> n.iota.map!(_ => readln);` claims to support forward, 
> bidirectional and random access (all read-only, as the argument 
> function returns by value) as well as slicing, but none of 
> these make any sense; all access primitives do exactly the same 
> thing, with the result being different every time. Even the 
> simplest invariants fail, such as `r.front == r.front`, and 
> `popFront`, `popBack` and slicing only has a binary effect, 
> whether or not the range is empty yet.

OK, I'm now beginning to understand how hacky is that.

> All the random number generator types in `std.random` are 
> infinite forward ranges of random numbers, which is completely 
> fine. For any PRNG `r`, `r.front == r.front` is true, and 
> remains the same number until `r.popFront()`, it correctly has 
> no length and is always non-empty (infinite range), and 
> `r.save` works correctly etc.

So, for both of my examples, support for desired behavior is 
provided at the different side: not a non-caching repeat for a 
given function but a range of lines or random numbers with the 
desired properties instead of such function.  Maybe that's 
usually the right thing to do in the general case, too...

>> Perhaps there's a wholly different way of thinking about this 
>> in which the first definition makes much more sense than then 
>> second one from the start.  If so, please share it.
>
> All you have to do is look at the signature of the function, 
> which is the primary part of its documentation:
>
> Repeat!T repeat(T)(T value);
>
> It takes one value of any type T, not a function pointer or 
> delegate that returns T. Even if you give it a function pointer 
> or delegate (which your example does not), it will simply 
> repeat that function pointer or delegate, never calling it.

So what I initially wanted is possible with something like (I 
just checked):
(&readln!(string)) . repeat(n) . map!(f => f('\n'))
However, I'm having a hard time trying to get rid of "!(string)" 
and "'\n'" to make something like the following work:
(&readln) . repeat(n) . map!(f => f())
Anyway, even the second line (which does not compile) looks 
cryptic a bit.  And it still has the problem of silently adding 
empty lines after end-of-file was reached.

> [1] ... in D we have something (slightly controversial) called 
> the `lazy` parameter storage class, but when used, it is 
> clearly visible in the signature of the function. 
> http://dlang.org/function.html#parameters

Thank you for the link.  This is indeed what was my other 
expectation for repeat.

Ivan Kazmenko.


More information about the Digitalmars-d-learn mailing list