Since I am currently working on proposition *product/2* functions for 
Enum/Stream I thought I may pipe in here.

When talking about Enumerables and Stream, there are a couple 
mathematics terms worth using. Specifically the terms for the number of 
elements of the set; a set's *cardinality. *

*Finite* cardinality*: *These are your normal sequences. For example, *Lists, 
Trees, Maps, and Functions that halt.* Anything with *finite* cardinality 
has an Integer Length. 
*Aleph-0* cardinality: These are your basic *Countable* infinite sequences. 
For example, *Natural numbers, Stream.**with_index, and so on. *Anything 
with *Aleph-0* cardinality doesn't have an Integer Length. 
*Aleph-1* or more: These are your *Uncountable* infinite sequences. For 
example, *All R**eal Numbers. *Anything with *Aleph-1* cardinality is very 
hard to reason with in a programming context. 

The proposed Enumerable.exhaustible?/1 is checking if the sequence is *Finite 
*or *Aleph-0. *Writing a function that returns *true* or *false* would be 
very hard. We would have to solve the halting problem to do so.

But from what I understand, the goal is to improve the **correctness** of 
Streams. The only thing I can think of that would be close to this is 
checking if something is a Stream or not.
Data enumerables will always halt. Stream enumerables may or may not halt. 

Something we can do is check if a Stream is *Aleph-0 *or *Aleph-1. *For 
example, concatenating two *Aleph-0 *Streams is not a valid operation 
because it makes the resulting Stream uncountable. *Unforchenetly,* as 
already established, you can't determine a Stream *is* or *isn't* countable 
without solving the halting problem.
   
So we are stuck with only being able to determine if an operation is *valid*, 
or is *maybe valid*. 

On Monday, July 24, 2017 at 2:28:00 AM UTC-7, José Valim wrote:
>
> Currently, both Enumerable.count/1 and Enumerable.member?/2 can return 
>> {:error, __MODULE__} to fall back on a naive linear implementation that 
>> takes neither countability nor exhaustibility into account––factors that 
>> Enumerable.reduce/3 doesn't entirely rely on. If we want to group these 
>> changes into the Enumerable module, this seem to me to be the place of 
>> leverage for breaking API changes.
>>
>
> The reason count/1 and member?/2 exist is to provide better than linear 
> time implementations. So I don't believe we need to change them and we 
> definitely can't remove them - since replacing them by any other construct 
> would remove the constant time benefits. For those functions, if they 
> return {:error, __MODULE__}, then they could fallback to an implementation 
> that guarantees terminability.
>
> - Enumerable.exhaustible?/1
>>
>>   Pure opt-in to denote non-negative access: raises if implemented as 
>> {:ok, false} in relevant functions, proceeds if {:ok, true} is returned, 
>> defaults to {:error, __MODULE__} for existing infinite loop behaviour. Uses 
>> the default for existing core types.
>>
>
> The access functions (fetch, at, etc) are not the only one that suffer 
> from this issue, any aggregation function, such as sum, max, min, etc will 
> have termination issues. As well as drop/take with negative values.
>
> We should also avoid double dispatching to functions: for example calling 
> Enumerable.exhaustible? and then Enumerable.reduce because of the double 
> dispatch cost. Protocol consolidation is available on production apps but 
> still not available during scripts, compilation time, etc. This is not an 
> Enumerable specific limitation. I would have added this exact same kind of 
> concerns if the Sequence implementation moved forward.
>
> The other limitation here is that some functions are actually quite hard 
> to guarantee they terminate. For example, Enum.flat_map/flat_map feels like 
> they terminate but they can return an infinite collection to be flattened, 
> which then means they won't terminate. What should be the default 
> implementation for those? We will either have false positives or false 
> negatives.
>  
>
>> - Enumerable.seek/2
>>
>>   Falls back to reduce/3 if not implemented, via a counter, re-implements 
>> Enum.at/{2, 3} and dependents, return {:error, __MODULE__} to fall back 
>> on reduce/3.
>>
>
> That sounds great to me. What if we call it Enumerable.fetch to mirror 
> Enum.fetch? It may return {:ok, found} | :error | {:error, __MODULE__} - 
> where the last one means to fallback to a linear-time implementation.
>
> I think at this point we can clearly treat them as two separate proposals. 
> We should guarantee termination regardless if we can optimize functions 
> such as fetch/2 and at/3 and vice-versa.
>
>

-- 
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 [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/elixir-lang-core/558c0d71-3276-4aba-a667-4e607b8515d4%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to