www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Infinite range of nullable elements

reply "Roland Hadinger" <rolandh.dlangforum maildrop.cc> writes:
At this moment I'm tempted to implement a function taking a range 
of elements E and returning an infinite range of Nullable!E.

With this function ("cushion" for a lack of better name) I could 
do:

     auto a = [0,1,2,3,4,5,6,7,8,9];

     foreach (e ; a.cushion.take(20))
         writeln(e); // exactly 20 elements

This would allow chaining together algorithms that need to look 
ahead in a range.

Here's how I would implement the basic behaviour (could be 
extended to also forward bidirectional and random access 
functions):

---
     auto cushion(R)(R r)
         if (isInputRange!R)
     {
         static if (isInfinite!R) { return r; } else {

             struct _Cushion(R)
             {
                 R r;

                 alias E = ElementType!R;
                 alias NE = Nullable!E;

                  property bool empty() { return false; }

                  property NE front()
                 {
                     return !r.empty ? NE(r.front) : NE();
                 }

                 void popFront()
                 {
                     if (!r.empty) r.popFront();
                 }
             }

             return _Cushion!R(r);
         }
     }

---

I didn't find anything like this Phobos. Did I miss something? Is 
this a bad idea for some reason?
Jul 17 2015
next sibling parent reply =?UTF-8?B?Ik3DoXJjaW8=?= Martins" <marcioapm gmail.com> writes:
On Friday, 17 July 2015 at 07:42:09 UTC, Roland Hadinger wrote:
 At this moment I'm tempted to implement a function taking a 
 range of elements E and returning an infinite range of 
 Nullable!E.

 [...]
Wouldn't it still require the algorithms to check if an element isNull()? Calling get() on a null element will assert(). I'm wondering why it asserts instead of throwing.
Jul 17 2015
parent "Roland Hadinger" <rolandh.dlangforum maildrop.cc> writes:
On Friday, 17 July 2015 at 10:19:22 UTC, Márcio Martins wrote:
 On Friday, 17 July 2015 at 07:42:09 UTC, Roland Hadinger wrote:
 At this moment I'm tempted to implement a function taking a 
 range of elements E and returning an infinite range of 
 Nullable!E.

 [...]
Wouldn't it still require the algorithms to check if an element isNull()?
Naturally. But this check can be done further down the function chain, so all the functions before will see an infinite range. I'm currently writing a lexer (big loop with two levels of switch statements inside) that needs to some looking ahead in multiple states. Normally, each of those lookaheads would require a check for "end of input". I want to avoid this because of the large number of states.
Jul 17 2015
prev sibling parent reply "anonymous" <anonymous example.com> writes:
On Friday, 17 July 2015 at 07:42:09 UTC, Roland Hadinger wrote:
 Here's how I would implement the basic behaviour (could be 
 extended to also forward bidirectional and random access 
 functions):

 ---
     auto cushion(R)(R r)
         if (isInputRange!R)
     {
         static if (isInfinite!R) { return r; } else {

             struct _Cushion(R)
             {
                 R r;

                 alias E = ElementType!R;
                 alias NE = Nullable!E;

                  property bool empty() { return false; }

                  property NE front()
                 {
                     return !r.empty ? NE(r.front) : NE();
                 }

                 void popFront()
                 {
                     if (!r.empty) r.popFront();
                 }
             }

             return _Cushion!R(r);
         }
     }

 ---

 I didn't find anything like this Phobos. Did I miss something?
The building blocks are there. You're `map`ping the original range to `Nullable`, and then you're `chain`ing an infinite range (`cycle`) of nulls behind. ---- import std.range: isInputRange; auto cushion(R)(R r) if (isInputRange!R) { import std.algorithm: map; import std.range: chain, cycle, ElementType, only; import std.typecons: Nullable; alias E = ElementType!R; alias NE = Nullable!E; return chain(r.map!NE, NE().only.cycle); } ----
Jul 17 2015
parent "Roland Hadinger" <rolandh.dlangforum maildrop.cc> writes:
On Friday, 17 July 2015 at 12:44:57 UTC, anonymous wrote:
 The building blocks are there. You're `map`ping the original 
 range to `Nullable`, and then you're `chain`ing an infinite 
 range (`cycle`) of nulls behind.

 ----
 import std.range: isInputRange;

 auto cushion(R)(R r)
     if (isInputRange!R)
 {
     import std.algorithm: map;
     import std.range: chain, cycle, ElementType, only;
     import std.typecons: Nullable;

     alias E = ElementType!R;
     alias NE = Nullable!E;

     return chain(r.map!NE, NE().only.cycle);
 }
 ----
Nice! I didn't think of using 'chain'.
Jul 17 2015