www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - streams to ranges adapters

reply Diego Martinelli <martinelli.diego gmail.com> writes:
Hi all!
I'm digging the documentation of phobos but I am still learning D and I can't
help
myself.
I feel like there's a lack of adapters between streams and ranges (something
like
istream_iterator/ostream_iterator in STL).

Just a bit of C++ to make my point:

#include <iostream>
#include <algorithm>
#include <vector>
#include <iterator>

using namespace std;  // just for convenience

int factorial(const int& n) {
  int result = 1;
  for (int i = 1; i <= n; ++i)
    result *= i;
  return result;
}

int main() {
  vector<int> v;

  copy(istream_iterator<int>(cin),
       istream_iterator<int>(),
       back_inserter(v));

  transform(v.begin(), v.end(),
            ostream_iterator<int>(cout, "\n"),
            factorial);

  return 0;
}

How'd you write an equivalent program in idiomatic D? I mean, I'd like an higher
level approach to foreach/readf. Am I missing something?

Thanks,
Diego
Sep 01 2010
next sibling parent Jonathan M Davis <jmdavisprog gmail.com> writes:
On Wednesday 01 September 2010 03:19:41 Diego Martinelli wrote:
 Hi all!
 I'm digging the documentation of phobos but I am still learning D and I
 can't help myself.
 I feel like there's a lack of adapters between streams and ranges
 (something like istream_iterator/ostream_iterator in STL).
A properly written stream type _is_ a range with no adaptors necessary. However, std.stream predates much of the range stuff in Phobos, so its implementation does not support ranges. The intention is to replace it with a streaming module that _does_ properly support ranges. However, it's on the TODO list and hasn't been done yet. IIRC, there's at least one implementation which has been discussed on the Phobos list which may end up as the replacement for std.stream, but it hasn't happened yet, so Phobos does not yet support using ranges with streams. - Jonathan M Davis
Sep 01 2010
prev sibling parent reply Peter Neubauer <peterneubauer2 gmail.com> writes:
On 09/01/2010 12:19 PM, Diego Martinelli wrote:
 Hi all!
 I'm digging the documentation of phobos but I am still learning D and 
I can't help
 myself.
 I feel like there's a lack of adapters between streams and ranges 
(something like
 istream_iterator/ostream_iterator in STL).
I've encountered a similar problem yesterday. It left me digging through the Phobos docs for an hour looking for an existing solution :-) Let's say I have a function (or any D expression,) and I want to turn consecutive calls to this function into range form. As an example, let's generate 10 random numbers between 30 and 50. My first attempt was something like this: import std.range; import std.random; void main () { writeln(take(recurrence!("uniform(30, 50)")(), 10)); } However, this doesn't work because recurrence refuses to take 0 arguments. Your post prompted me to steal some boilerplate code from the Phobos source and write this: struct Rangeof(T) { T delegate() _dg; T _buffer; bool _called = false; this(T delegate() dg) { _dg = dg; } property bool empty() { return false; } void popFront() { if (!_called) { _buffer = _dg(); } _called = false; } property ref T front() { if (!_called) { _buffer = _dg(); _called = true; } return _buffer; } } auto rangeof(F)(F func) if (isCallable!F) { return Rangeof!(ReturnType!(F))(func); } Rangeof!(T) rangeof(T)(lazy T exp) if (!isCallable!T) { T callexp (){ return exp; } return rangeof(&callexp); } Now you can turn any expression or function into a proper input range, compatible with std.range stuff. Example: writeln(take(rangeof(uniform(30, 50)), 10)); At the risk of overshooting my goal, here's an additional overload for std.range.take which can now also "take" from a function: auto my_take(F)(F input, size_t n) if (!isInputRange!F && isCallable!F) { return Take!(Rangeof!(ReturnType!(F)))(rangeof(input), n); } Which means one less step in usage: writeln(my_take({ return uniform(30, 50); }, 10)); Oh, and I didn't test my code at all, apart from those examples. Feel free to use it if you like. -Peter
Sep 01 2010
parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
On Wed, Sep 1, 2010 at 20:54, Peter Neubauer <peterneubauer2 gmail.com>wrote:

 I've encountered a similar problem yesterday. It left me digging through
 the Phobos docs for an hour looking for an existing solution :-) Let's say I
 have a function (or any D expression,) and I want to turn consecutive calls
 to this function into range form. As an example, let's generate 10 random
 numbers between 30 and 50. My first attempt was something like this:
(snip)
 Oh, and I didn't test my code at all, apart from those examples. Feel free
 to use it if you like.
It's a good idea and a common need: to transform a generator into a range. It could be adapted to work with callable structs and classes, too, if you need it to hold state. Philippe
Sep 01 2010