Proposal: Stream.shift :: {element, Stream.t}

46 views
Skip to first unread message

w.m.w...@student.rug.nl

unread,
Mar 24, 2017, 4:53:23 PM3/24/17
to elixir-lang-core
The Stream module contains many functions to work with lazily evaluated sequences. 
However, functions like `Stream.map`, `Stream.reduce`, `Stream.transform`, only make sense when the stream is the primary part of our recursion.
If we are doing something where we want to take an item from the (possibly infinite) stream only every once in a while, then we're out of luck. Functions like `Stream.take` only return a result, but discard the unevaluated tail of the stream.

So I would propose a function that, when called, would return a tuple: As first element of the tuple, the outcome of calculating the first item of the stream, and as second element the unevaluated stream without the first element included.
In the case the stream is empty, `nil` should be returned.

I was thinking `Stream.shift` as name for this thing, but there are quite probably better names to give this as well. Semantics is of course more important than syntax.

In any case, I think this is an addition that is very much in line with what Streams already do, but it will make it easier to work with them for certain kinds of algorithms, such as programs where we are parsing files but there is no natural way to split this file into lines or equally-sized chunks.

José Valim

unread,
Mar 24, 2017, 5:25:02 PM3/24/17
to elixir-l...@googlegroups.com
I would recommend trying out an implementation

 I am afraid that, once started, a Stream can no longer be modified, so if you use Stream.shift(...), your only option is to use Stream.shift(...) until the Stream is done or halt it. It effectively becomes an iterator API.



José Valim
Skype: jv.ptec
Founder and Director of R&D

--
You received this message because you are subscribed to the Google Groups "elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-core+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/a7b5734b-66b9-495b-9c55-fdd318fb6899%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

w.m.w...@student.rug.nl

unread,
Mar 24, 2017, 9:30:05 PM3/24/17
to elixir-lang-core, jose....@plataformatec.com.br
Interesting... I've tried out writing a small proof-of-concept that piggybacks on the possibilities of Enumerable's `:suspended`: https://gist.github.com/Qqwy/e8fbabc496e4ffe05d75e8770f4323ce

This works, but you are indeed fully correct that the continuation you receive from these calls cannot be called a stream itself: The computation on the stream is already in full effect (it being implemented as recursive functions calling each other in Stream.Reducers), so something like Stream.shift cannot be interspersed with any of the stream transformation functions.

This could be wrapped in an e.g. `%Iterator{}` struct, but then we end up with a whole new thing all together, which is probably too heavy to add to Elixir unless there is an extremely good reason to.

The only other approach I can think of, is using a separate process, which will use `receive` to block computing the next element of the stream until it is asked for it by means of a message.
This, too, is probably a too roundabout way to add to the core language.

~Qqwy

On Friday, March 24, 2017 at 10:25:02 PM UTC+1, José Valim wrote:
I would recommend trying out an implementation

 I am afraid that, once started, a Stream can no longer be modified, so if you use Stream.shift(...), your only option is to use Stream.shift(...) until the Stream is done or halt it. It effectively becomes an iterator API.



José Valim
Skype: jv.ptec
Founder and Director of R&D

On Fri, Mar 24, 2017 at 9:53 PM, <w.m.w...@student.rug.nl> wrote:
The Stream module contains many functions to work with lazily evaluated sequences. 
However, functions like `Stream.map`, `Stream.reduce`, `Stream.transform`, only make sense when the stream is the primary part of our recursion.
If we are doing something where we want to take an item from the (possibly infinite) stream only every once in a while, then we're out of luck. Functions like `Stream.take` only return a result, but discard the unevaluated tail of the stream.

So I would propose a function that, when called, would return a tuple: As first element of the tuple, the outcome of calculating the first item of the stream, and as second element the unevaluated stream without the first element included.
In the case the stream is empty, `nil` should be returned.

I was thinking `Stream.shift` as name for this thing, but there are quite probably better names to give this as well. Semantics is of course more important than syntax.

In any case, I think this is an addition that is very much in line with what Streams already do, but it will make it easier to work with them for certain kinds of algorithms, such as programs where we are parsing files but there is no natural way to split this file into lines or equally-sized chunks.

--
You received this message because you are subscribed to the Google Groups "elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com.

José Valim

unread,
Mar 25, 2017, 4:49:10 AM3/25/17
to elixir-lang-core, w.m.w...@student.rug.nl
Yes, maybe a library that provides a stateless and a stateful iterator.
--
Reply all
Reply to author
Forward
0 new messages