[Lib, Feature] Индекс в макросе foreach
От: VladD2 Российская Империя www.nemerle.org
Дата: 22.07.10 23:05
Оценка: 64 (3)
Расширил (в ревизии 9023) функциональность стандартного макроса foreach. Теперь в нем можно объявлять (необязательный) индекс. Индекс — это целочисленная переменная (типа int) которая получает начальное значение 0 (ноль) и последовательно увеличивается после каждой итерации цикла.

Новый синтаксис foreach-а:
"foreach" "(" variableOrPattran "in" collection ("with" indexName)? ")" body


Примеры использования:

using SCG = System.Collections.Generic;
using System.Console;
using Nemerle.Imperative;

module Program
{
  Main() : void
  {
    WriteLine("-------------- two-dimensional array");
    
    def xs = array.[2][["Nemerle", "C#", "C++"], ["VB", "Delphi", "Lisp"]];
    
    foreach (x in xs with i)
      WriteLine($"$(i + 1). $x");

    WriteLine("-------------- single-dimensional array");
    
    def xs = array["Nemerle", "Erlang", "Unknown!!!"];
    
    foreach (x in xs with i)
    {
      WriteLine($"$(i + 1). $x");
      
      when (i == 1)
        break;
    }

    WriteLine("-------------- list[T]");
    
    def xs = ["I", "love", "Nemerle", "!"];
    
    foreach (x in xs with i)
      WriteLine($"$(i + 1). $x");

    WriteLine("-------------- System.Collections.Generic.IEnumerable[T]");
    
    def xs = SCG.List(["apple", "pear", "plum"]); // SCG.IEnumerable[string]
    
    foreach (x in xs with i)
      WriteLine($"$(i + 1). $x");
  }
}

/*
BEGIN-OUTPUT
-------------- two-dimensional array
1. Nemerle
2. C#
3. C++
4. VB
5. Delphi
6. Lisp
-------------- single-dimensional array
1. Nemerle
2. Erlang
-------------- list[T]
1. I
2. love
3. Nemerle
4. !
-------------- System.Collections.Generic.IEnumerable[T]
1. apple
2. pear
3. plum
END-OUTPUT
*/


Если кому-то не нравится предложенный синтаксис, предлагайте свои варианты.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: [Lib, Feature] Индекс в макросе foreach
От: _nn_ www.nemerleweb.com
Дата: 23.07.10 12:29
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Расширил (в ревизии 9023) функциональность стандартного макроса foreach. Теперь в нем можно объявлять (необязательный) индекс. Индекс — это целочисленная переменная (типа int) которая получает начальное значение 0 (ноль) и последовательно увеличивается после каждой итерации цикла.


По аналогии с обычным foreach, почему нет IterI для IEnumerable[T] , а есть только для array[T], list[T] ?
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[2]: [Lib, Feature] Индекс в макросе foreach
От: VladD2 Российская Империя www.nemerle.org
Дата: 23.07.10 13:46
Оценка:
Здравствуйте, _nn_, Вы писали:

__>По аналогии с обычным foreach, почему нет IterI для IEnumerable[T] , а есть только для array[T], list[T] ?


Никто не написал. Лично я предпочитаю использовать foreach. Он быстрее и при отладке удобнее.

ЗЫ

Вообще, было бы неплохо если бы кто-то сел и осмыслил стандартную библиотеку. Подумал бы чего не хватает, что лишнего. Ну, и как результат этой работы произвел бы рефактироин и написал бы недостающие методы.

Я добавлял функции в библиотеку только когда мне самому требовалась та или иная функция. Посему иногда добавлялись специализированные версии для тех же массивов, так как именно для них функции и были нужны. Код для list[T] вообще писался обособленно, так что там тоже много странностей.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: [Lib, Feature] Индекс в макросе foreach
От: _nn_ www.nemerleweb.com
Дата: 26.07.10 08:40
Оценка:
Здравствуйте, VladD2, Вы писали:

Я вот никак не могу найти подходящий раздел в вики для foreach with и foreach/for/while otherwise.
Может в http://nemerle.org/CsharpDiff ?

Заодно и пример foreach c сопоставлением c образцом.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[3]: [Lib, Feature] Индекс в макросе foreach
От: Klapaucius  
Дата: 26.07.10 11:41
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Вообще, было бы неплохо если бы кто-то сел и осмыслил стандартную библиотеку. Подумал бы чего не хватает, что лишнего. Ну, и как результат этой работы произвел бы рефактироин и написал бы недостающие методы.


В принципе, я могу посмотреть и вынести некоторые предложения на обсуждение. Ну и недостающие методы написать. Я как раз последнее время думал, как должна выглядеть стандартная библиотека ФЯ для .NET. В какие сроки это нужно сделать?
... << RSDN@Home 1.2.0 alpha 4 rev. 1446>>
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[4]: [Lib, Feature] Индекс в макросе foreach
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.07.10 13:52
Оценка:
Здравствуйте, Klapaucius, Вы писали:

K>В принципе, я могу посмотреть и вынести некоторые предложения на обсуждение. Ну и недостающие методы написать. Я как раз последнее время думал, как должна выглядеть стандартная библиотека ФЯ для .NET. В какие сроки это нужно сделать?


Это нужно сделать. Чем быстрее, тем (конечно) лучше. Но конкретных сроков нет.

Мои пожелания такие. Специализированные версии функций (сделанные для увеличения быстродействия) нужно оставить. Если они не покрывают всех вариантов, написать универсальные. Так же нужно продумать общую идеологию именования. При этом нужно избежать конфликтов (вроде тех что были между методами расширениями вроде ToList).
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: [Lib, Feature] Индекс в макросе foreach
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.07.10 13:58
Оценка: 1 (1)
Здравствуйте, _nn_, Вы писали:

__>Я вот никак не могу найти подходящий раздел в вики для foreach with и foreach/for/while otherwise.

__>Может в http://nemerle.org/CsharpDiff ?

Сюда тоже конечно надо. Но для всех макросов из стандартной библиотеки нужно завести отдельный раздел.

__>Заодно и пример foreach c сопоставлением c образцом.


Я считаю, что надо создать отдельную страницу для всех стандартных макросов, назовем их "statment". Учитывая, что у нас уже есть страница для макросов-операторов, по аналогии нужно создать страничку http://nemerle.org/Macro_statments

На этой страничке для каждого statment-а нужно создать по разделу (чтобы в оглавление входили). Ну, а далее нужно для каждого:
1. Описание синтаксиса в нотации PEG (раз уж мы на него со временем перейдем).
2. Описание на английском.
3. Примеры использования (в виде юнит-тестов).
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: [Lib, Feature] Индекс в макросе foreach
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.07.10 14:16
Оценка:
Здравствуйте, _nn_, Вы писали:

__>Я вот никак не могу найти подходящий раздел в вики для foreach with и foreach/for/while otherwise.

__>Может в http://nemerle.org/CsharpDiff ?

Кстати, о http://nemerle.org/Macro_operators туда для каждого макро-оператора нужно вписать приоритет. Кроме того такую же страничку нужно создать для встроенных операторов, где так же указать приоритеты. Причем между этими страничками нужно сделать перекрестные ссылки (чтобы люди могли при просмотре одних переходить к просмотру других).
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: [Lib, Feature] Индекс в макросе foreach
От: catbert  
Дата: 27.07.10 08:14
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Если кому-то не нравится предложенный синтаксис, предлагайте свои варианты.


Мне он нравится, но мне в голову пришел более естественный:

foreach(x[i] in seq)
{
}

(ну, может он и не очень естественный, но что-то в нем есть, мне кажется)
Re[2]: [Lib, Feature] Индекс в макросе foreach
От: hardcase Пират http://nemerle.org
Дата: 27.07.10 08:52
Оценка: 6 (1)
Здравствуйте, catbert, Вы писали:

C>Здравствуйте, VladD2, Вы писали:


VD>>Если кому-то не нравится предложенный синтаксис, предлагайте свои варианты.


C>Мне он нравится, но мне в голову пришел более естественный:


C>foreach(x[i] in seq)

C>{
C>}

C>(ну, может он и не очень естественный, но что-то в нем есть, мне кажется)


Мне больше нравится вот так:
foreach(x in seq index i)
/* иЗвиНите зА неРовнЫй поЧерК */
Re[3]: [Lib, Feature] Индекс в макросе foreach
От: Mckey Россия  
Дата: 27.07.10 09:09
Оценка:
Здравствуйте, hardcase, Вы писали:

H>Мне больше нравится вот так:

H>
H>foreach(x in seq index i) 
H>


Да пожалуй с Index-ом самое понятное...
Делай добро и бросай его в воду...
Re[3]: [Lib, Feature] Индекс в макросе foreach
От: _FRED_ Черногория
Дата: 27.07.10 15:23
Оценка:
Здравствуйте, hardcase, Вы писали:

H>Мне больше нравится вот так:

H>foreach(x in seq index i)


А вот такое компилятор разберёт:
H>foreach(x in seq index index)

?
Help will always be given at Hogwarts to those who ask for it.
Re[3]: [Lib, Feature] Индекс в макросе foreach
От: VladD2 Российская Империя www.nemerle.org
Дата: 28.07.10 00:20
Оценка:
Здравствуйте, hardcase, Вы писали:

H>Мне больше нравится вот так:

H>
H>foreach(x in seq index i) 
H>


Если это сделать, то придется делать index ключевым словом. Меж тем довольно часто index используется для именования переменных. Лишние ключевые слова — это плохо. Уже и так достало, что нельзя назвать переменную type или list.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: [Lib, Feature] Индекс в макросе foreach
От: Klapaucius  
Дата: 28.07.10 07:19
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Мои пожелания такие. Специализированные версии функций (сделанные для увеличения быстродействия) нужно оставить. Если они не покрывают всех вариантов, написать универсальные.


VD>Так же нужно продумать общую идеологию именования. При этом нужно избежать конфликтов (вроде тех что были между методами расширениями вроде ToList).


А какие есть пределы свободы по переименованию? Эти методы ведь много гдк используются уже? Я так понимаю, что придется делать обновленную библиотеку в другом пространстве имен, а нынешние методы оставить для совместимости, ну и может пометить как Obsolete.
Потому что там сейчас есть странные методы вроде
Map[From, To](this source : SCG.IEnumerable[From], convert : From -> To) : list[To]

В данном случае метод сочетает Map с конверсией в другую структуру данных и должен был бы называться, по идее, MapToList, и закрывает имя для более привычного мапа (тип коллекции у Map на входе и на выходе одинаковый во всех библиотеках, пожалуй, кроме этой), который называется поэтому MapLazy.
Также много унаследованных имен из ML, которые не имеют большого смысла в языке с перегрузкой имен функций по сигнатурам: IterI (естественно, отличается от Iter сигнатурой, так что имя может быть и без I), Map2 (ML-имя в Linq это Zip, а в Haskell ZipWith, потому как это действительно скорее Zip, чем Map, но дело не в этом а в двойке, без которой тоже можно обойтись), та же история и с FoldI.
Далее, нужно ли делать имена в более развернутом стиле .NET — библиотек вроде ForEach или с сокращениями как в ML вроде Iter? Иметь и развернутую и сокращенную версию?
Как быть с именами из System.Linq? Я так понял, что предполагается пользоваться методами расширениями из новой библиотеки совместно с линковскими и, в таком случае, делать ли, для единообразия, методы Select и Where для массивов и списков, для которых сейчас есть Map и Filter (не хотелось бы, лично мне имена линковских методов не особенно нравятся.
Предполагается ли делать только методы расширения или еще и иерархию интерфейсов для иммутабельных контейнеров и каковы приоритеты?
Нужны ли еще иммутабельные структуры данных? Пальчиковые деревья, например?
Чем полагается тестировать? Где можно посмотреть гайдлайны по оформлению кода, принятые в проекте?
... << RSDN@Home 1.2.0 alpha 4 rev. 1446>>
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[6]: [Lib, Feature] Индекс в макросе foreach
От: VladD2 Российская Империя www.nemerle.org
Дата: 28.07.10 12:35
Оценка:
Здравствуйте, Klapaucius, Вы писали:

K>А какие есть пределы свободы по переименованию?


Переименовывать лучше не надо. Только если в этом есть особая необходимость, и то имеет смысл обсудить с народом.

K>Эти методы ведь много гдк используются уже? Я так понимаю, что придется делать обновленную библиотеку в другом пространстве имен, а нынешние методы оставить для совместимости, ну и может пометить как Obsolete.

K>Потому что там сейчас есть странные методы вроде
K>
K>Map[From, To](this source : SCG.IEnumerable[From], convert : From -> To) : list[To]
K>


Тут конечно нужно заметить тип возвращаемого значения наSCG.IEnumerable[To], а данную функцию переименовать в MapToNList.

K>В данном случае метод сочетает Map с конверсией в другую структуру данных и должен был бы называться, по идее, MapToList,


Ага, только в MapToNList, так как List уже занят SCG.List[T].

K>и закрывает имя для более привычного мапа (тип коллекции у Map на входе и на выходе одинаковый во всех библиотеках, пожалуй, кроме этой), который называется поэтому MapLazy.


Не MapLazy — отражает тот факт, что обработка будет отложенной.

K>Также много унаследованных имен из ML, которые не имеют большого смысла в языке с перегрузкой имен функций по сигнатурам: IterI (естественно, отличается от Iter сигнатурой, так что имя может быть и без I),


Тут не совсем все так просто. Дело в том, что хотя перегрузка и есть, но есть и кортежи. Они вносят неоднозначность. Некоторые перегруженные функции конфликтуют. Я доработал алгоритм вывода типов одной эвристикой которая разруливать подобные ситуации, но она очень тяжеловесная (это приводит к тормозам) и не всегда хорошо работает (например, в режиме интеграции когда выражение может быть незаконченным).

Так что эти имена лучше оставить. За одно будет более понятно, что происходит.

K>Map2 (ML-имя в Linq это Zip, а в Haskell ZipWith, потому как это действительно скорее Zip, чем Map, но дело не в этом а в двойке, без которой тоже можно обойтись),


На счет Zip согласен. Но тут есть еще одна (более важная) проблема! Zip будет конфликтовать с методом-расширением из 4-го фрэймворка. А нам как раз это неприемлемо. На нужно сделать так, чтобы новое пространство имен (или старое) корректно сочеталось с пространством имен System.Linq. В линке есть много интересного и нужно сделать так чтобы наша методы расширения не конфликтовали с линковскми.

K>та же история и с FoldI.


А с ним то что? Я бы его оставил именно в таком виде. Только для всех типов реализовал бы.

K>Далее, нужно ли делать имена в более развернутом стиле .NET — библиотек вроде ForEach или с сокращениями как в ML вроде Iter?


Нет, не нужно. Опять же от части из соображения возможных конфликтов. Но так же и соображения компактности. Все же функциональный код должен быть компактным, так как часто его пишут в длину, а не в глубину.

K>Иметь и развернутую и сокращенную версию?


Думаю — это лишнее. Удлиннять нужно только если имя не однозначно. Например от Rev и RevMap я бы отказался в пользу Reverse и ReverseMap.

K>Как быть с именами из System.Linq?


Обязательно избегать конфликта с ним. Тестировать все методы с этим пространством имен. Иначе использование библиотеки превратится в мучение.

K>Я так понял, что предполагается пользоваться методами расширениями из новой библиотеки совместно с линковскими


Именно!

K>и, в таком случае, делать ли, для единообразия, методы Select и Where для массивов и списков, для которых сейчас есть Map и Filter (не хотелось бы, лично мне имена линковских методов не особенно нравятся.


Не делать. Но даже не из соображений "нравится / не нравится", а из соображений бесконфликтности.

K>Предполагается ли делать только методы расширения или еще и иерархию интерфейсов для иммутабельных контейнеров и каковы приоритеты?


Интерфейсы уже были. От них отказались. Все равно стандартные коллекции их не поддерживают. Так что не надо. Ну, если только найдутся серьезные аргументы для их введения.

K>Нужны ли еще иммутабельные структуры данных? Пальчиковые деревья, например?


Я не знаю что за пальчиковые деревья, но неизменяемые структуры конечно нужны. Тот же list[T] ведь тоже неизменяемая структура.

K>Чем полагается тестировать?


Компилятор тестами.

K>Где можно посмотреть гайдлайны по оформлению кода, принятые в проекте?


Ой. За базу бери Соглашения по оформлению кода команды RSDN. Ну, а для специфичного используй стиль из Nemerle.Collections.n.

ЗЫ

По уму нужно писать соглашения прямо для немерла. Необходимость уже назрела и перезрела.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: [Lib, Feature] Индекс в макросе foreach
От: Klapaucius  
Дата: 29.07.10 09:47
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Переименовывать лучше не надо. Только если в этом есть особая необходимость, и то имеет смысл обсудить с народом.


Ну это понятно.

VD>Не MapLazy — отражает тот факт, что обработка будет отложенной.


Ну, если Map для IEnumerable будет выбирать в рантайме, какой из специализированных методов использовать то да, нужен метод, который всегда non strict, а не в зависисмости от того, получается ли скастить IEnumerable к массиву, например.

VD>Дело в том, что хотя перегрузка и есть, но есть и кортежи. Они вносят неоднозначность. Некоторые перегруженные функции конфликтуют.


Т.е. фактически использовать преимущества перегрузки по сигнатурам нельзя?

VD>На счет Zip согласен. Но тут есть еще одна (более важная) проблема! Zip будет конфликтовать с методом-расширением из 4-го фрэймворка.


Ну, тогда можно называть ZipWith или ZipMap. Но если по типу функции перегрузку лучше не определять, то хотя-бы по разному числу аргументов она сработает? Т.е. всякие имена с тройками, четверками и т.д. не понадобятся?
И надо думать, как называть простой Zip, который возвращает список кортежей. В linq такого зипа нет и зипом называется ZipWith.

K>>та же история и с FoldI.

VD>А с ним то что?

Ну, я предполагал сделать перегрузку по типу функции. Теперь понятно, что этого лучше не делать. С другой стороны, если сигнатуру Iter(V * int -> ()) и Iter(V -> ()) действительно сложно различить, то в чем проблема различать (U * V * int -> U) и (U * V -> U) даже если U и V — кортежи?

VD>Все же функциональный код должен быть компактным


Да, согласен. Просто распространена противоположная точка зрения. Вон в F# IterI переименовали в IterateIndexed ну и все прочее в таком же роде.

VD>Интерфейсы уже были. От них отказались. Все равно стандартные коллекции их не поддерживают. Так что не надо. Ну, если только найдутся серьезные аргументы для их введения.


Ну, если будет несколько функциональных структур данных — для них пригодится и соотвествующая иерархия интерфейсов. Да и для стандартных коллекций можно иметь обертки только для чтения и "псевдоиммутабельные" вроде StringBuilder-а где метод, добавляющий элемент возвращает не (), а ссылку на измененный по месту билдер. Т.е. иметь обертку только для чтения, и мутабельную обертку для функционального кода с фолдами и сканами, (для которых можно сделать интерфейс IUnique с возможностью добавить в будущем проверки компилятора и ворнинги, для случаев, когда такая псевдофункциональная изменяемая коллекция используется не как уникальный тип).

VD>Я не знаю что за пальчиковые деревья,


Finger Tree. На их основе можно делать, например, последовательности с добавлением и в конец и в начало за O(1) и логарифмической сложностью конкатенации или кучи с O(1) Min и Max.
... << RSDN@Home 1.2.0 alpha 4 rev. 1446>>
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[8]: [Lib, Feature] Индекс в макросе foreach
От: VladD2 Российская Империя www.nemerle.org
Дата: 29.07.10 15:54
Оценка:
Здравствуйте, Klapaucius, Вы писали:

VD>>Не MapLazy — отражает тот факт, что обработка будет отложенной.


K>Ну, если Map для IEnumerable будет выбирать в рантайме, какой из специализированных методов использовать то да, нужен метод, который всегда non strict, а не в зависисмости от того, получается ли скастить IEnumerable к массиву, например.


Ну, так MapLazy будет работать лениво по любому. А Map будут работать не лениво (не знаю как это лучше по-русски назвать) и тогда рантайм-выбор не будет проблемой.

Хотя возможно я тебя не верно понял.

K>Т.е. фактически использовать преимущества перегрузки по сигнатурам нельзя?


Можно но не надо этим злоупотреблять. Если функция отличается семантически, то имеет смысл отражать это в названии.
Потом сегодняшинй алгоритм разруливать большую часть ситуаций. Проблема только в том, что это не быстро и в случае некорректного кода труднее выявлять ошибки.

Хороший пример проблематичного и совершенно ненужного метода как раз Select из Linq-а:
IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector)
IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, int, TResult> selector)

Вторая перегрузка приводит к тому, что когда мы работаем с кортежами (а мы с ними работаем часто) немерл не может выяснить что же мы хотим... использовать другую перегрузку и кортеж в TResult или использовать вторую перегрузку (разложив кортеж по параметрам). Я кое-что подкрутил в компиляторе, так что теперь эту проблему можно обойти. Но в случаях наличия ошибок в коде проблема вылезает.

K>Ну, тогда можно называть ZipWith или ZipMap.


Второй вариант мне больше нравится. Отражает суть.

K>Но если по типу функции перегрузку лучше не определять, то хотя-бы по разному числу аргументов она сработает?


Как раз по типам перегрузка работает отлично. А вот по количеству (что я продемонстрировал выше) иногда случаются проблемы. Тут дело в преобразовании кортежа в параметры методов.

Если же говорить о Linq-е, то там идет чистый конфликт. Ты ведь будешь описывать метод-расширение Zip с той же сигнатурой. А это чистый конфликт.

K>Т.е. всякие имена с тройками, четверками и т.д. не понадобятся?


Скажем так. Если они ни с чем не конфликтуют, то не понадобятся. Если тип параметров коллекция, то проблем не будет скорее всего.

K>И надо думать, как называть простой Zip, который возвращает список кортежей. В linq такого зипа нет и зипом называется ZipWith.


Ага.
Может ZipTuple или ZipToTuple?

K>>>та же история и с FoldI.

VD>>А с ним то что?

K>Ну, я предполагал сделать перегрузку по типу функции. Теперь понятно, что этого лучше не делать. С другой стороны, если сигнатуру Iter(V * int -> ()) и Iter(V -> ()) действительно сложно различить, то в чем проблема различать (U * V * int -> U) и (U * V -> U) даже если U и V — кортежи?


Я уже об этом говорил. Как раз это вызвает проблемы. Если в Linq мы ничего с этим сделать не можем, то тут лучше явно ввести IterI. За одно код читать легче будет.

VD>>Все же функциональный код должен быть компактным


K>Да, согласен. Просто распространена противоположная точка зрения. Вон в F# IterI переименовали в IterateIndexed ну и все прочее в таком же роде.


Ну, нас их корпоротивные проблемы волновать не должны. Нам лучше поступать так как нам же кажется логичнее. Чем логичнее будет библиотека, тем проще ее будет освоить. По Линку, кстати, вопросов в форумах выше крыши. Так что даже привычные SQL-ные имена не особо то помогают.

Кстати, как одно из решение — это отказаться от Iter вообще. В Линке аналога тоже нет. И его авторы это обосновывают как раз тем, что это не функциональная фича. Наш foreach весьма мощен. Еще бы научить его Zip заменять (тот что тюплы клеет) и вообще не ясно будет зачем нужны все эти Iter-ы.

K>Ну, если будет несколько функциональных структур данных — для них пригодится и соотвествующая иерархия интерфейсов.


А что это даст на практике? Я же говорю. Уже было... Толку — 0.

K>Да и для стандартных коллекций можно иметь обертки только для чтения и "псевдоиммутабельные" вроде StringBuilder-а где метод, добавляющий элемент возвращает не (), а ссылку на измененный по месту билдер.


В StringBuilder-е с этим как раз бороться приходится. Если структура изменяемая, то с этим уже ничего не поделаешь. К тому же у нас почти для всего есть неизменяемые аналоги. Вот их интерфейс тоже причесать бы.

K>Т.е. иметь обертку только для чтения, и мутабельную обертку для функционального кода с фолдами и сканами, (для которых можно сделать интерфейс IUnique с возможностью добавить в будущем проверки компилятора и ворнинги, для случаев, когда такая псевдофункциональная изменяемая коллекция используется не как уникальный тип).


Что-то я не понял. Ты предлагаешь эмулировть ФП на изменяемых структурах?

VD>>Я не знаю что за пальчиковые деревья,


K>Finger Tree. На их основе можно делать, например, последовательности с добавлением и в конец и в начало за O(1) и логарифмической сложностью конкатенации или кучи с O(1) Min и Max.


Да много чего можно напридумывать. Только лучше сделать одно дело хорошо, чем 10 на половину. Если уж мы говорим о интерфейсе библиотеки, то не надо отвлекаться на реализацию новых алгоритмов и т.п.

Вот тут как-то Вольфхаунд тоже предложил для наших внутренних коллекций использовать 2-3-деревья. В теории офигительный выигрыш в производительности. На практике его и в микроскоп не разглядеть (если говорить о компиляторе, который не помешало бы ускорить).

Если будет желание и/или необходимость, все это потом можно добавить. Но смешивать с данной задачей это не надо.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[9]: [Lib, Feature] Индекс в макросе foreach
От: Klapaucius  
Дата: 30.07.10 11:04
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Ну, так MapLazy будет работать лениво по любому. А Map будут работать не лениво (не знаю как это лучше по-русски назвать)


Я предпочитаю использовать слово "энергично".

VD>и тогда рантайм-выбор не будет проблемой.

VD>Хотя возможно я тебя не верно понял.

Да, именно это я и имел в виду. В принципе это нормально, но может быть метод ToLazy или там AsSeq — который возвращает итератор, который нельзя скастить к другим коллекциями и гарантированно делающий весь последующий конвейер лениво выполняющимся рациональнее. При написании Linq-запросов я часто добавляю или убераю форсирование вычислений — которое там по умолчанию нестрогое методом ToArray, и смотрю как это влияет на производительность. Легче, по-моему, добавить или убрать ToLazy, чем меняьть у всей цепочки методов имена с MapLazy().FilterLazy().MapLazy() на Map().Filter().Map() и обратно. Хотя, понятное дело, дополнительный автомат в ToLazy добавляет некоторый оверхед по производительности.

VD>Ты ведь будешь описывать метод-расширение Zip с той же сигнатурой. А это чистый конфликт.


Вообще-то Zip ведь не имеет параметра функции — так что отличие от линковского Zip явное. Разве что они в будущем добавят перегруженную версию зипа без функционального парметра — в чем я лично сомневаюсь.

VD>Может ZipTuple или ZipToTuple?


Есть в этом какая-то тавтология. Да и длинновато.

K>>Ну, я предполагал сделать перегрузку по типу функции. Теперь понятно, что этого лучше не делать. С другой стороны, если сигнатуру Iter(V * int -> ()) и Iter(V -> ()) действительно сложно различить, то в чем проблема различать (U * V * int -> U) и (U * V -> U) даже если U и V — кортежи?

VD>Я уже об этом говорил. Как раз это вызвает проблемы. Если в Linq мы ничего с этим сделать не можем, то тут лучше явно ввести IterI. За одно код читать легче будет.

Ну я понимаю, почему V -> U и T*int -> U вызывают проблемы, потому что V может быть кортежем, да и по типу коллекции две сигнатуры можно, в принципе, разрешить. Но в случае с (U * V * int -> U) и (U * V -> U) ситуация, по идее, должна быть проще — тип аккумулятора U — один и тот же и на входе и на выходе из функции.

VD>Кстати, как одно из решение — это отказаться от Iter вообще.


Я считаю, что его нужно оставить. Когда методы выстраиваются в цепочку-конвеер — она читается слева-направо и сверху вниз:
Map(f).Filter(p).Map(g).Iter(do);

А foreach сбивает эту логичную последовательность. Получается, что последнеее действие с продвигающиейся по конвейеру коллекцией описано в начале.
foreach(x in Map(f).Filter(p).Map(g)) do;

Iter может быть короче, чем foreach в случае передачи функции, а не лямбды вроде
$[0..5].Iter(WriteLine);

Iter можно специализировать для структуры данных, для более эффективного обхода, а в foreach из стандартной библиотеки просто так специализированную обработку не вставить.
Наконец, Iter — функция и первоклассный объект, который можно передать, а foreach — нет.
В общем, считаю что для Iter место есть.

VD>это обосновывают как раз тем, что это не функциональная фича.


Они заблуждаются. Это вполне функциональная фича, потому как Iter можно передатьв ФВП и вернуть из ФВП. То, что он возвращает () — не показатель. Да и присутствует Iter в большинстве библиотек функциональных языков, включая и Haskell, в котором называется forM_.

VD>Еще бы научить его Zip заменять (тот что тюплы клеет)


Да, это было бы полезно. Кстати, по поводу Zip-а, в Haskell есть такое расширение для лист компрехеншн, называется Parallel List Comprehensions.
В nemerle бы такое тоже не помешало. Или уже есть?

VD>А что это даст на практике? Я же говорю. Уже было... Толку — 0.


Что-то я такого не припоминаю. Как эта иерархия выглядела? Да и разнообразием иммутабельных структур данных библиотека пока не радует — не уидивительно, что иерархия интерфейсов не пригождалась.

VD>Если структура изменяемая, то с этим уже ничего не поделаешь.


Можно на самом деле. Есть стандартные подходы, когда мутабельная структура вроде массива обрабатывается в ФЯ стиле, методами, возвращающими измененную по месту структуру, а после обработки "замораживается" иммутабельной оберткой. Часто бывает, что хэш-таблица или массив используются в два этапа — на первом наполняются, а на втором только читаются.

VD>Вот их интерфейс тоже причесать бы.


Да, конечно.

VD>Что-то я не понял. Ты предлагаешь эмулировть ФП на изменяемых структурах?


Тут и эмелировать ничего не надо. Изменения структуры не просто вполне совместимы с ФП, но даже являются чистыми, при условии, что ссылка на струкутуру только одна, что неплохо бы проверять компилятором.

VD>Только лучше сделать одно дело хорошо, чем 10 на половину. Если уж мы говорим о интерфейсе библиотеки, то не надо отвлекаться на реализацию новых алгоритмов и т.п.


понятное дело, что все это для следующих этапов, менее приоритетных по сравнению с приведением в порядок методов-расширений и существующих структур.

VD>Вот тут как-то Вольфхаунд тоже предложил для наших внутренних коллекций использовать 2-3-деревья. В теории офигительный выигрыш в производительности. На практике его и в микроскоп не разглядеть (если говорить о компиляторе, который не помешало бы ускорить).


Ну, офигительный — это преувеличение. там некторый выигрыш по памяти и времени прохода за счет того, что основание логарифма в асимтотических оценках сложности больше двойки. Тут ситуация другая — элемент в конец добавляется за O(1), а не за O(N) как в список и конкатенация относительно эффективнам (логарифм от длины более короткой из двух объединяемых последовательностей). Понятно, что константа выше списочной, но на конкатенации больших списков и добавлении элементов в конец больших списков выигрыш будет существенным.

VD>Если будет желание и/или необходимость, все это потом можно добавить. Но смешивать с данной задачей это не надо.


Смешивание и не предполагается. Все планируется делать этапами: на первом методы-расширения первой необходимости для списков, энумераторов и массивов (возможно, строк и т.д.) и приведение в порядок интерфейса списка, на следующем этапе доведение набора методов расширений до уровня библиотек ФЯ вроде хаскеля или F#-а, дальше добавочные иммутабельные структуры данных.
... << RSDN@Home 1.2.0 alpha 4 rev. 1476>>
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[10]: [Lib, Feature] Индекс в макросе foreach
От: VladD2 Российская Империя www.nemerle.org
Дата: 30.07.10 15:51
Оценка:
Здравствуйте, Klapaucius, Вы писали:

K>Я предпочитаю использовать слово "энергично".


Откровенно говоря и ленво, и энергично не отражают суть. Особенно "энергично". Здесь более подошло бы отложено, то есть deferred или delayed. Но тут точно не ясно с антонимом, да и боюсь многие наших лингвистических изысков не поймут .

VD>>и тогда рантайм-выбор не будет проблемой.

VD>>Хотя возможно я тебя не верно понял.

K>Да, именно это я и имел в виду. В принципе это нормально, но может быть метод ToLazy или там AsSeq — который возвращает итератор, который нельзя скастить к другим коллекциями и гарантированно делающий весь последующий конвейер лениво выполняющимся рациональнее. При написании Linq-запросов я часто добавляю или убераю форсирование вычислений — которое там по умолчанию нестрогое методом ToArray, и смотрю как это влияет на производительность. Легче, по-моему, добавить или убрать ToLazy, чем меняьть у всей цепочки методов имена с MapLazy().FilterLazy().MapLazy() на Map().Filter().Map() и обратно. Хотя, понятное дело, дополнительный автомат в ToLazy добавляет некоторый оверхед по производительности.


Да, похоже ты прав. Я добавлял Lazy версии именно с целью получить такое поведение в условиях когда функции вовращают черти-что. Если все будет единообразно, то отдельного ToLazy будет достаточно.

VD>>Ты ведь будешь описывать метод-расширение Zip с той же сигнатурой. А это чистый конфликт.


K>Вообще-то Zip ведь не имеет параметра функции — так что отличие от линковского Zip явное. Разве что они в будущем добавят перегруженную версию зипа без функционального парметра — в чем я лично сомневаюсь.


Резонно. Но тогда конфликт может начаться уже в головах. Люди будут путать разные по семантике фукнции. Так что я бы все же предпочел нарочито другое имя описывающее суть происходящего.

VD>>Может ZipTuple или ZipToTuple?


K>Есть в этом какая-то тавтология. Да и длинновато.


Что касается длинны, то вряд ли такие вещи часто применяться будут.
А что до тавтологии, то, как я уже говорил, Zip люди будут путать с Zip-ом линка.
Плюс раз уж у нас язык с перегрузкой, то перегружать нужно только идентичные алгоритмы, а это уже сильно разные.

K>Ну я понимаю, почему V -> U и T*int -> U вызывают проблемы, потому что V может быть кортежем, да и по типу коллекции две сигнатуры можно, в принципе, разрешить. Но в случае с (U * V * int -> U) и (U * V -> U) ситуация, по идее, должна быть проще — тип аккумулятора U — один и тот же и на входе и на выходе из функции.


Дык компилятор думать не умет. Он использует тупой перебор вариантов. Так что он будет рассматривать раскрытие макроса и для V.

Откровенно говоря временами я подумывал об отказе от неявного преобразования кортежей в параметрах.

K>Я считаю, что его нужно оставить. Когда методы выстраиваются в цепочку-конвеер — она читается слева-направо и сверху вниз:

K>
K>Map(f).Filter(p).Map(g).Iter(do);
K>


Я всю такую конвейрезацию к чертям удаляю когда с кодом разбираюсь. Все же императив не нужно маскировать под ФП. Плюс в отладке в сто раз проще, но это уже конечно больше проблема кривого отладчика.

В прочем, я не против. Оставляй. Это был как вариант. Лично я все равно буду предпочитать foreach.

K>А foreach сбивает эту логичную последовательность. Получается, что последнеее действие с продвигающиейся по конвейеру коллекцией описано в начале.

K>
K>foreach(x in Map(f).Filter(p).Map(g)) do;
K>


Да нет тут уже никакого конвейера. Он оборвался. Далее мы перебираем значения и императивно их обрабатываем.

K>Iter может быть короче, чем foreach в случае передачи функции, а не лямбды вроде

K>
K>$[0..5].Iter(WriteLine);
K>


Короче еще не значит лучше. Еще раз повторюсь императив должно быть видно. Плюс циклы не фига совать в стек. Это усложняет отладку.

Ладно. Еще раз повторю. Против наличия Iter я ничего не имею. Я его использование не люблю.

K>Iter можно специализировать для структуры данных, для более эффективного обхода, а в foreach из стандартной библиотеки просто так специализированную обработку не вставить.


Лучше реализовывать итераторы (с yield которые). В коде компилятора как раз часто вместо итераторов реализовывали Iter, что приводило к тому, что потом код рефакторить сложно.

Тут я уже просто настаиваю, что для всего для чего есть Iter должен быть так же реализован и IEnumerable[T].

K>Наконец, Iter — функция и первоклассный объект, который можно передать, а foreach — нет.


Меня больше убедили аргументы чувака из команды линка где он объяснял почему в линке нет foreach. Аргумент был одинм, но железным. Линк — это ФП, а в ФП нет места императиву.

VD>>это обосновывают как раз тем, что это не функциональная фича.


K>Они заблуждаются. Это вполне функциональная фича, потому как Iter можно передатьв ФВП и вернуть из ФВП.


В том то и проблема, что можно, а не нужно! Передавать имератив в ФВП — это весьма опасный шаг. Потом фига два поймешь откуда побочные эффекты полезли. Именно это и есть главный аргумент против форича.

K> То, что он возвращает () — не показатель. Да и присутствует Iter в большинстве библиотек функциональных языков, включая и Haskell, в котором называется forM_.


Ну, хаскель трогать не надо. Тат все замонадовано по самые помидоры. И форыча у них нет.

VD>>Еще бы научить его Zip заменять (тот что тюплы клеет)


K>Да, это было бы полезно. Кстати, по поводу Zip-а, в Haskell есть такое расширение для лист компрехеншн, называется Parallel List Comprehensions.

K>В nemerle бы такое тоже не помешало. Или уже есть?

Есть http://en.wikibooks.org/wiki/F_Sharp_Programming/Computation_Expressions

VD>>А что это даст на практике? Я же говорю. Уже было... Толку — 0.


K>Что-то я такого не припоминаю. Как эта иерархия выглядела?


Погляди древние версии скажем Hashtable. Там (если не ошибаюсь) эти интерейсы присутствовали. В них были разные Map, Iter и т.п.

K>Можно на самом деле. Есть стандартные подходы, когда мутабельная структура вроде массива обрабатывается в ФЯ стиле, методами, возвращающими измененную по месту структуру, а после обработки "замораживается" иммутабельной оберткой. Часто бывает, что хэш-таблица или массив используются в два этапа — на первом наполняются, а на втором только читаются.


Ну, так у нас на то есть классы и инкапсуляция.

VD>>Что-то я не понял. Ты предлагаешь эмулировть ФП на изменяемых структурах?


K>Тут и эмелировать ничего не надо. Изменения структуры не просто вполне совместимы с ФП, но даже являются чистыми, при условии, что ссылка на струкутуру только одна, что неплохо бы проверять компилятором.


Ну, до этого еще далеко. Если только зависимые типы реализуем. Или еще что-то подобное.


VD>>Вот тут как-то Вольфхаунд тоже предложил для наших внутренних коллекций использовать 2-3-деревья. В теории офигительный выигрыш в производительности. На практике его и в микроскоп не разглядеть (если говорить о компиляторе, который не помешало бы ускорить).


K>Ну, офигительный — это преувеличение. там некторый выигрыш по памяти и времени прохода за счет того, что основание логарифма в асимтотических оценках сложности больше двойки. Тут ситуация другая — элемент в конец добавляется за O(1), а не за O(N) как в список и конкатенация относительно эффективнам (логарифм от длины более короткой из двух объединяемых последовательностей). Понятно, что константа выше списочной, но на конкатенации больших списков и добавлении элементов в конец больших списков выигрыш будет существенным.


Как я понял из википедии 2-3_tree — это и есть твои фингертри, только в чуть упрощенном виде. К тому же "существенный" — это опять же оценка для случая консервации сферо-коня в вакуме. Важна скорость работы программы. Если доступ к ключам у нас отнимал 1% времени, то мы никак не выиграем даже этой величины заменив реализацию дерева на более эффективную.

K>Смешивание и не предполагается. Все планируется делать этапами: на первом методы-расширения первой необходимости для списков, энумераторов и массивов (возможно, строк и т.д.) и приведение в порядок интерфейса списка, на следующем этапе доведение набора методов расширений до уровня библиотек ФЯ вроде хаскеля или F#-а, дальше добавочные иммутабельные структуры данных.


Ну, тогда ОК. А то эти структуры могут все время съесть.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: [Lib, Feature] Индекс в макросе foreach
От: Ka3a4oK  
Дата: 30.07.10 17:54
Оценка:
Не нужны эти макросы(foreach c индексом, foreach/else). Это уже не синтаксический сахар, а какой-то лишний жир.
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.