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