È possibile implementare un IEnumerable infinito senza usare yield con solo codice C #?

5

Motivazione

L'idea principale è esplorare e comprendere i limiti di quanto si può andare lontano con i primitivi LINQ di base (Select, SelectMany, Concat, ecc.). Queste primitive possono essere tutte considerate operazioni funzionali su un tipo di sequenza teorica. Prendendo esempi da Haskell:

  • Select "alza" una funzione nella sequenza (come fmap in Haskell)
  • Concat è composizione
  • Aggregate è il catamorfismo (piega)
  • del tipo di sequenza
  • SelectMany 'estrae' le informazioni dalla sequenza (il collegamento Monad, l'operazione >>= )
  • ecc. (e sono sicuro che ci sono migliori astrazioni per quanto sopra)

Quindi la domanda è se le operazioni di sequenza di base (Enumerable) in C # siano sufficienti per costruire una sequenza infinita. Più concretamente è il seguente problema:

Problema

Sono curioso di sapere se c'è un modo per implementare qualcosa di equivalente al seguente, ma senza usare yield :

IEnumerable<T> Infinite<T>()
{
    while (true) { yield return default(T); }
}

È possibile fare causa usando solo gli operatori LINQ integrati?

La risposta breve è che teoricamente sì, ma praticamente non a causa di come viene implementato Linq (causando overflow dello stack).

Ecco perché qui ci sono regole meno restrittive:

Regole

In alternativa, una domanda meno restrittiva andrebbe secondo le regole

  1. Non puoi utilizzare direttamente la parola chiave yield
  2. Utilizza solo C # direttamente - nessun codice IL, nessuna costruzione dinamica ecc.
  3. Puoi utilizzare solo la lib di base di .NET (solo mscorlib.dll , System.Core.dll ? non sai che altro includere). Tuttavia, se trovi una soluzione con alcuni degli altri assembly .NET (WPF ?!), sono anche interessato.
  4. Non implementare IEnumerable o IEnumerator.

Note

Un esempio di definizione teoricamente corretta è:

IEnumerable<int> infinite = null;
infinite = new int[1].SelectMany(x => new int[1].Concat(infinite));

Questo è " correct " ma colpisce StackOverflowException dopo 14399 iterazioni tramite enumerable (non proprio infinito).

Penso che non ci sia modo di farlo a causa del compilatore del C # mancanza di ottimizzazione della ricorsione della coda . Una prova sarebbe carina:)

    
posta sinelaw 07.11.2013 - 04:48
fonte

3 risposte

7

Anche se la tua affermazione fosse vera, dimostrando che sarebbe irrealizzabile, perché la dimostrazione dovrebbe passare attraverso tutte le implementazioni di IEnumerable nel framework e provare per ognuna di quelle che non può essere infinita.

E la tua affermazione in realtà non è vera, c'è almeno un'implementazione di IEnumerable nel framework che può essere infinita: BlockingCollection.GetConsumingEnumerable() :

Quello che dovresti fare è creare un% co_de limitato che viene inserito in un ciclo infinito da un thread separato. Chiamando BlockingCollection verrà quindi restituito un GetConsumingEnumerable() infinito:

var source = new BlockingCollection<int>(1);
Task.Run(() => { while (true) source.Add(1); });
return source.GetConsumingEnumerable();
    
risposta data 07.11.2013 - 09:32
fonte
2

Certo. IEnumerable è fondamentalmente solo una chiamata a IEnumerator. Implementare un IEnumerator in cui la funzione MoveNext imposta semplicemente un valore interno su un valore casuale e Current restituisce tale valore casuale.

    
risposta data 07.11.2013 - 17:11
fonte
-1

Ecco un iteratore praticamente infinito:

using System;
using System.Linq;

public class Test
{
    public static void Main()
    {
        var infiniteIterator =
            Enumerable.Range(Int32.MinValue, Int32.MaxValue)
                      .SelectMany(i => Enumerable.Range(Int32.MinValue, Int32.MaxValue))
                      .SelectMany(i => Enumerable.Range(Int32.MinValue, Int32.MaxValue))
                      .SelectMany(i => Enumerable.Range(Int32.MinValue, Int32.MaxValue))
                      .Select(i => default(int));

        foreach (var infinite in infiniteIterator)
            Console.WriteLine(infinite);
    }
}
    
risposta data 07.11.2013 - 05:06
fonte

Leggi altre domande sui tag