логика неумолима! IEnumerable
не поддерживает Clone
, и вам нужно Clone
, поэтому вы не должны использовать IEnumerable
.
Или, точнее, вы не должны использовать его в качестве фундаментальной основы для работы с интерпретатором Scheme. Почему бы вместо этого не создать тривиальный неизменный связанный список?
public class Link<TValue>
{
private readonly TValue value;
private readonly Link<TValue> next;
public Link(TValue value, Link<TValue> next)
{
this.value = value;
this.next = next;
}
public TValue Value
{
get { return value; }
}
public Link<TValue> Next
{
get { return next; }
}
public IEnumerable<TValue> ToEnumerable()
{
for (Link<TValue> v = this; v != null; v = v.next)
yield return v.value;
}
}
Обратите внимание, что метод ToEnumerable
обеспечивает удобное использование стандартным способом C #.
Чтобы ответить на ваш вопрос:
Может кто-нибудь предложить реалистичный,
полезный пример IEnumerable
объект, который не сможет
обеспечить эффективный метод "Clone ()"?
Это было бы проблемой с
конструкция "урожайность"?
IEnumerable может отправиться в любую точку мира за своими данными. Вот пример, который читает строки из консоли:
IEnumerable<string> GetConsoleLines()
{
for (; ;)
yield return Console.ReadLine();
}
Есть две проблемы с этим: во-первых, функция Clone
не была бы особенно простой для записи (и Reset
была бы бессмысленной). Во-вторых, последовательность бесконечна - что вполне допустимо. Последовательности ленивы.
Другой пример:
IEnumerable<int> GetIntegers()
{
for (int n = 0; ; n++)
yield return n;
}
Для обоих этих примеров «обходной путь», который вы приняли, вряд ли будет полезен, поскольку он просто исчерпает доступную память или зависнет навсегда. Но это вполне допустимые примеры последовательностей.
Чтобы понять последовательности C # и F #, вам нужно посмотреть списки в Haskell, а не списки в Scheme.
Если вы думаете, что бесконечные вещи - это красная сельдь, как насчет чтения байтов из сокета:
IEnumerable<byte> GetSocketBytes(Socket s)
{
byte[] buffer = new bytes[100];
for (;;)
{
int r = s.Receive(buffer);
if (r == 0)
yield break;
for (int n = 0; n < r; n++)
yield return buffer[n];
}
}
Если есть некоторое количество байтов, отправляемых по сокету, это не будет бесконечной последовательностью. И все же писать клон для этого было бы очень сложно. Как компилятор сгенерирует реализацию IEnumerable, чтобы сделать это автоматически?
Как только был создан Clone, оба экземпляра теперь должны были работать из буферной системы, которую они использовали. Это возможно, но на практике это не нужно - это не то, как эти виды последовательностей предназначены для использования. Вы рассматриваете их чисто «функционально», как значения, рекурсивно применяя к ним фильтры, а не «обязательно» запоминая расположение в последовательности. Это немного чище, чем манипуляции с низким уровнем car
/ cdr
.
Дополнительный вопрос:
Интересно, какой самый низкий уровень?
"примитив (ы)" мне нужно, чтобы
все, что я мог бы сделать с
IEnumerable в моем Scheme интерпретаторе
может быть реализовано в схеме, а
чем как встроенный.
Короткий ответ, я думаю, будет выглядеть в Абельсон и Суссман и, в частности, часть о потоках . IEnumerable
- это поток, а не список. И они описывают, как вам нужны специальные версии карты, фильтра, накопления и т. Д. Для работы с ними. Они также сталкиваются с идеей объединения списков и потоков в разделе 4.2.