Помнится, как-то затрагивалась тема касательно того, что неплохо было бы добавить специальный образец для Enumerable. Вот, собственно, интересно — как бы мог выглядеть этот образец (предполагается, что будет возможен "рекурсивный" разбор на манер списка с образцом голова-хвост x::xs). Т.е. синтаксис, поведение?
Здравствуйте, Воронков Василий, Вы писали:
ВВ>Помнится, как-то затрагивалась тема касательно того, что неплохо было бы добавить специальный образец для Enumerable. Вот, собственно, интересно — как бы мог выглядеть этот образец (предполагается, что будет возможен "рекурсивный" разбор на манер списка с образцом голова-хвост x::xs). Т.е. синтаксис, поведение?
Самый примитивный способ, до которого я додумался, это Seq(head, tail) и Seq() (ну, или IEnumerable(head, tail) и IEnumerable).
Поведение: при первом (только при первом!) Seq-матче вызывается метод MoveNext(), и если возвращается true, Current матчится с head а tail — с самим объектом Enumerable. Если возвращается false, запускается ветка с Seq(). Достоинства: не вводится новая пунктуация (вообще не вводится новый синтаксис, можно сказать), образцы аналогичны с образцами рекордов. Недостатки: выглядит не так круто, как матчинг по спискам.
Re[2]: IEnumerable и паттерн матчинг
От:
Аноним
Дата:
20.05.10 15:08
Оценка:
Здравствуйте, catbert, Вы писали:
C>Самый примитивный способ, до которого я додумался, это Seq(head, tail) и Seq() (ну, или IEnumerable(head, tail) и IEnumerable).
Но в душе хочется F-шарповских Active Patterns, только покруче.
Здравствуйте, catbert, Вы писали:
C>Самый примитивный способ, до которого я додумался, это Seq(head, tail) и Seq() (ну, или IEnumerable(head, tail) и IEnumerable). C>Поведение: при первом (только при первом!) Seq-матче вызывается метод MoveNext(), и если возвращается true, Current матчится с head а tail — с самим объектом Enumerable. Если возвращается false, запускается ветка с Seq(). C>Достоинства: не вводится новая пунктуация (вообще не вводится новый синтаксис, можно сказать), образцы аналогичны с образцами рекордов. C>Недостатки: выглядит не так круто, как матчинг по спискам.
Тут проблема какая... В принципе можно и вообще без tail обойтись, собственно, мы же с одним и тем же объектом работаем. Но это-то и таит в себе опасности. Скажем если у нас справа будет что-нибудь типа func1(seq) && func2(seq), то в func2 энумератор уже будет передан с совершенно другим состоянием, чем в func1. Т.е. прямолинейная реализация типа seq(x, y, z) как-то невольно располагает к побочным эффектам.
Здравствуйте, catbert, Вы писали:
C>Недостатки: выглядит не так круто, как матчинг по спискам.
Ещё одним недостатком является немудрое поведение в таком матче:
match (xs)
{
| Seq(x, Seq(y, Seq()) ) => // blah blah
| Seq(x, Seq(y, Seq(z, Seq()) ) ) => // а тут проблема, ведь на предыдущей ветке вызвали MoveNext три раза, соответственно Current "уже не тот"
}
Исправляется такое, например, кешированием первых елементов xs.
Вообще, паттерн-матчинг по изменяемым структурам, как я уже говорил — гадкая вещь
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, Воронков Василий, Вы писали: ВВ>>Как тут быть? А>Тут целая квантовая теория выходит Чтобы прочитать енумератор, надо изменить его состояние. От этого печального факта никуда не денешся.
Самый тупой способ делать Reset на каждом вхождении match-а. Но если подумать, то даже с Reset-ом проблема, ибо мы энумератор к нам мог прийти уже с каким-то состоянием, отличном от нулевого. Причем это будет типичная ситуация — при рекурсивном разборе sequence-а.
Т.е. нужен какой-то умный reset? Или хитрое клонирование энумераторов?
Здравствуйте, catbert, Вы писали:
C>Исправляется такое, например, кешированием первых елементов xs. C>Вообще, паттерн-матчинг по изменяемым структурам, как я уже говорил — гадкая вещь
Тут проблема не в изменяемости структуры, а в том, что эта структура инкапсулирует некоторое состояние, которое приходится менять во время матча.
А с массивами таких проблем нет, ты, конечно, можешь там сам что-нибудь накосячить, ну так и варианты могут быть вполне себе изменяемыми структурами.
Здравствуйте, Воронков Василий, Вы писали:
ВВ>Самый тупой способ делать Reset на каждом вхождении match-а. Но если подумать, то даже с Reset-ом проблема, ибо мы энумератор к нам мог прийти уже с каким-то состоянием, отличном от нулевого. Причем это будет типичная ситуация — при рекурсивном разборе sequence-а. ВВ>Т.е. нужен какой-то умный reset? Или хитрое клонирование энумераторов?
PeekValue(enu : Seq[T]) : option[T * Seq[T]]
{
if (enu.MoveNext()) Some(enu.Current, Append(enu.Current, enu)) else None();
}
Append(elem : T, enu : Seq[T]) : Seq[T]
{
yield elem;
foreach (elem in enu) yield enu; // так делать ужасно, но это можно переписать без генератора
}
Здравствуйте, Воронков Василий, Вы писали:
ВВ>Самый тупой способ делать Reset на каждом вхождении match-а. Но если подумать, то даже с Reset-ом проблема, ибо мы энумератор к нам мог прийти уже с каким-то состоянием, отличном от нулевого.
Мне кажется, матчить следует только IEnumerable. Не зря в Микрософте разделили эти интерфейсы.
Здравствуйте, Воронков Василий, Вы писали:
ВВ>Здравствуйте, catbert, Вы писали:
C>>Кстати, можно брать новые IEnumerator'ы для каждого матча.
ВВ>Ну вот это пока единственный рабочий вариант. Но для этого придется их как-то клонировать.
Зачем клонировать? Мы матчим IEnumerable. Для каждого матча можно вызвать GetEnumerator().
Здравствуйте, Ziaw, Вы писали:
ВВ>>Здравствуйте, catbert, Вы писали: C>>>Кстати, можно брать новые IEnumerator'ы для каждого матча. ВВ>>Ну вот это пока единственный рабочий вариант. Но для этого придется их как-то клонировать. Z>Зачем клонировать? Мы матчим IEnumerable. Для каждого матча можно вызвать GetEnumerator().
А чем это отличается от полного Reset? Состояние-то надо сохранять.
Здравствуйте, Воронков Василий, Вы писали:
ВВ>Помнится, как-то затрагивалась тема касательно того, что неплохо было бы добавить специальный образец для Enumerable. Вот, собственно, интересно — как бы мог выглядеть этот образец (предполагается, что будет возможен "рекурсивный" разбор на манер списка с образцом голова-хвост x::xs). Т.е. синтаксис, поведение?
Спор ни о чём: пытаетесь нефункциональщину запихнуть в функциональный язык. Тогда уж надо просто скопировать инумератор в список, а потом уже с ним базар устраивать...
Здравствуйте, FDSC, Вы писали:
FDS>Здравствуйте, Воронков Василий, Вы писали:
ВВ>>Помнится, как-то затрагивалась тема касательно того, что неплохо было бы добавить специальный образец для Enumerable. Вот, собственно, интересно — как бы мог выглядеть этот образец (предполагается, что будет возможен "рекурсивный" разбор на манер списка с образцом голова-хвост x::xs). Т.е. синтаксис, поведение?
FDS>Спор ни о чём: пытаетесь нефункциональщину запихнуть в функциональный язык. Тогда уж надо просто скопировать инумератор в список, а потом уже с ним базар устраивать...
1. Спора нет
2. Идею о паттерн-матчинге для энумераторов выдвигал вообще-то Влад
3. Немерле — не функциональный язык, а гибридный
4. Каким бы странным вам это не показалось, но генераторы (реализацией которых являются итераторы в дотнете) пришли именно из ФЯ
Здравствуйте, catbert, Вы писали:
ВВ>>Самый тупой способ делать Reset на каждом вхождении match-а. Но если подумать, то даже с Reset-ом проблема, ибо мы энумератор к нам мог прийти уже с каким-то состоянием, отличном от нулевого. C>Мне кажется, матчить следует только IEnumerable. Не зря в Микрософте разделили эти интерфейсы.
Разделили не зря, но как можно матчить только IEnumerable, я не очень понимаю. Состояние-то все же надо сохранять для рекурсивного разбора. А состояние хранит именно энумератор.