Re[9]: LINQ как шаг к функциональному программированию
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 19.01.09 12:57
Оценка:
Здравствуйте, Undying, Вы писали:

U>Т.е. вариантов стало больше, видя код SomeFunction(someClass), мы теперь, чтобы определить тип someClass, в одном случае должны посмотреть в левую часть объявления переменной, в другом — в правую, в третьем — и вовсе воспользоваться intellisense, а, значит, читабельность стала хоть и чуточку, но хуже. А учитывая, что объявлений переменных в коде очень много, эта чуточка суммируется и становится довольно существенной.


И почему до сих пор думаете что читаемость зависит от информации о типах?

Получается что любой язык с динамической типизацией вообще нечитаем?
Re[9]: LINQ как шаг к функциональному программированию
От: Ziggi111 Россия  
Дата: 19.01.09 13:08
Оценка: +3 :)))
Здравствуйте, Undying, Вы писали:

U>2) Переменная получена из функции по месту использования:


U>
U>SomeFunction(GetSomeClass());
U>


U>Здесь взглядом определить тип переменной нельзя, всегда нужно использовать intellisense.


Можно. Ибо как уже писали выше, если функции обзывать не как попало, то всё понятно и без intellisense. Ну если конечно функция Дай_Хлеб() не возвращает колесо_от_самолёта.
Re[8]: LINQ как шаг к функциональному программированию
От: Undying Россия  
Дата: 19.01.09 13:08
Оценка:
Здравствуйте, Qbit86, Вы писали:

Q>Вообще-то, абстракция — это отказ от несущественных деталей. И во многом благодаря абстракции читабельность улучшается.


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

      if (true)
      {
        LightSynchronizer<int> sync = new LightSynchronizer<int>(this,
          delegate
          {
            return modifyDeviceGridSynch.VisibleDataRegion.Height;
          },
          delegate (int visibleHeight)
          {
            int rowHeight = modifyDeviceGridSynch.RowHeight;
            modifyDevicePanel.Height = modifyDevicePanel.Height + (rowHeight - visibleHeight);
          },
          TimeSpan.FromMilliseconds(100));
      }

      if (true)
      {
        LightSynchronizer<string> sync = new LightSynchronizer<string>(this,
          delegate
          {
            return Passport2.Model.GetValue(modifyDevice);
          },
          delegate(string model)
          {
            foreach (string dataType in modelBox.GetNewDataTypes(model))
              Passport2.StoragePeriod.SetProperty(modifyDevice, 14, dataType);
          });
      }


проще читается и модифицируется, нежели канонический:

      CreateHeightModifyPanelSynchronizer();
      CreateDeviceDataTypeSynchronizer();


Естественно при условии, что этот код не дублируется и его повторное использование невероятно или крайне мало вероятно.

Другое дело, что хотелось бы нормальной поддержки такого кода от intellisense и компилятора, примерно в таком виде:

      inline("HeightModifyPanelSynchronizer")
      {
        ...
      }

      inline("DeviceDataTypeSynchronizer")
      {
        ...
      }


Соответственно с возможностью перемещения по этим inline в студии, аналогичной сегодняшнему перемещению по функциям, отражением inline в stacktrace и т.п.
Re: LINQ как шаг к функциональному программированию
От: Аноним  
Дата: 21.01.09 10:59
Оценка:
Здравствуйте, Чистяков Влад (VladD2), Вы писали:

ЧВV>Данное решение не создает особых проблем на практике, за исключением того, что вызов делегата медленнее, чем мог бы быть, так как приходится анализировать лишнюю информацию.


На основании чего сделан вывод? Вы смотрели генерируемый машинный код? Можете ли предложить более оптимальный, если бы делегат хранил одну ссылку (при этом поддерживая прочий функционал делегатов)?
Re[2]: LINQ как шаг к функциональному программированию
От: VladD2 Российская Империя www.nemerle.org
Дата: 21.01.09 13:44
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, Чистяков Влад (VladD2), Вы писали:


ЧВV>>Данное решение не создает особых проблем на практике, за исключением того, что вызов делегата медленнее, чем мог бы быть, так как приходится анализировать лишнюю информацию.


А>На основании чего сделан вывод?


Вообще-то было бы неплохо более точно указывать суть вопроса. Приходится только догадываться о чем он.
Как я понял из контекста речь о словах "за исключением того, что вызов делегата медленнее, чем мог бы быть".

А>Вы смотрели генерируемый машинный код?


В том числе и его.

А>Можете ли предложить более оптимальный, если бы делегат хранил одну ссылку (при этом поддерживая прочий функционал делегатов)?


Если исключить поддержку множественных вызовов, которая на практике не нужна, то обычный класс с виртуальным методом работает быстрее. Да и в реализации он проще. Так устроены функциональные типы в F#, Nemerle и в Scala. Учитывая, что конкретные экземпляры можно помечать как sealed потенциально такое решением может быть оптим в плоть до прямого не виртуального вызова, а то и подставлено по месту. Единственная его проблема — в больших проектах получается очень много "рабочих" классов, что в итоге приводит к замедлению загрузки сборок. Но прекомпилированные (ngen-ом) сборки грузятся довольно шустро. Если же реализовывать это на уровне виртуальной машины, можно добиться быстрой загрузки. С делегатами ведь такой проблемы нет...
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[9]: LINQ как шаг к функциональному программированию
От: hugo Австрия  
Дата: 21.01.09 14:02
Оценка:
Здравствуйте, Undying, Вы писали:

U>Года два назад, когда был молодой и читал много умных книжек, я тоже так думал. Однако на практике оказалось, что обычно даже такой код:


U>
U>      if (true)
U>      {
U>        LightSynchronizer<int> sync = new LightSynchronizer<int>(this,
U>          delegate
U>          {
U>            return modifyDeviceGridSynch.VisibleDataRegion.Height;
U>          },
U>          delegate (int visibleHeight)
U>          {
U>            int rowHeight = modifyDeviceGridSynch.RowHeight;
U>            modifyDevicePanel.Height = modifyDevicePanel.Height + (rowHeight - visibleHeight);
U>          },
U>          TimeSpan.FromMilliseconds(100));
U>      }

U>      if (true)
U>      {
U>        LightSynchronizer<string> sync = new LightSynchronizer<string>(this,
U>          delegate
U>          {
U>            return Passport2.Model.GetValue(modifyDevice);
U>          },
U>          delegate(string model)
U>          {
U>            foreach (string dataType in modelBox.GetNewDataTypes(model))
U>              Passport2.StoragePeriod.SetProperty(modifyDevice, 14, dataType);
U>          });
U>      }
U>


U>проще читается и модифицируется, нежели канонический:


Я, наверное, еще очень молодой, но ИМХО этот код не читается вообще .
Re[3]: LINQ как шаг к функциональному программированию
От: MxKazan Португалия  
Дата: 21.01.09 14:14
Оценка:
Здравствуйте, VladD2, Вы писали:

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

Как это не нужна? А события?
Re[9]: LINQ как шаг к функциональному программированию
От: hugo Австрия  
Дата: 21.01.09 14:17
Оценка: +1
Здравствуйте, Undying, Вы писали:


VD>>А какая разница есть она или нет? Ты код перестаешь читать если значение прямо в параметр (без переменной) передается?


U>В шарпе 2.0 есть три варианта объявления переменной:


На Erlang нет ни одного варианта, просто нету анотаций типов. Мне не мешает.
Как уже здесь говорили, наибольшая проблема — это понимание алгоритма. Conway's Game of Life, все, что я использую там — это int, массивы int'ов, таплы int'ов и всевозможные комбинации с int'ами. Здесь информация о типе перестает играть какую-либо роль вообще и начинаешь уделять внимание именам переменных и функций. И вынужден следить за этим постоянно. А имя переменной, это то, что видно на протяжении всего участка кода. Чего нельзя сказать о типе. Имея нормальное именование, за которыи ты просто уже обязан следить, начинаешь действительно читать код, а не копаться в нем.
Re[9]: LINQ как шаг к функциональному программированию
От: C...R...a...S...H  
Дата: 21.01.09 15:47
Оценка: +2
Здравствуйте, Undying, Вы писали:

U>
U>      if (true)
U>      {
U>        LightSynchronizer<int> sync = new LightSynchronizer<int>(this,
U>          delegate
U>          {
U>            return modifyDeviceGridSynch.VisibleDataRegion.Height;
U>          },
U>          delegate (int visibleHeight)
U>          {
U>            int rowHeight = modifyDeviceGridSynch.RowHeight;
U>            modifyDevicePanel.Height = modifyDevicePanel.Height + (rowHeight - visibleHeight);
U>          },
U>          TimeSpan.FromMilliseconds(100));
U>      }

U>      if (true)
U>      {
U>        LightSynchronizer<string> sync = new LightSynchronizer<string>(this,
U>          delegate
U>          {
U>            return Passport2.Model.GetValue(modifyDevice);
U>          },
U>          delegate(string model)
U>          {
U>            foreach (string dataType in modelBox.GetNewDataTypes(model))
U>              Passport2.StoragePeriod.SetProperty(modifyDevice, 14, dataType);
U>          });
U>      }
U>


Читал этот код и плакал
Undying доказывает что var — зло при этом сам же пишет который читать вообще не реально, НО самое интересное, что он так же скрывает типы переменных

delegate
{
    return modifyDeviceGridSynch.VisibleDataRegion.Height;
}
delegate
{
    return Passport2.Model.GetValue(modifyDevice);
}

Какой интересно тип результата?

Следуя вашим рассуждениям данный код должне быть написан так:
delegate
{
     int result = modifyDeviceGridSynch.VisibleDataRegion.Height;
     return result;
}
delegate
{
     int result = Passport2.Model.GetValue(modifyDevice);
     return result;
}
Там было написано русским по белому...
Re: LINQ как шаг к функциональному программированию
От: SuhanovSergey  
Дата: 21.01.09 16:34
Оценка: 1 (1)
var result = array1.Aggregate((first, second) => first + ", " + second);

Это всё конечно изящно, но оно вылетает с исключением при пустой последовательности.
Re[10]: LINQ как шаг к функциональному программированию
От: Undying Россия  
Дата: 22.01.09 04:44
Оценка: -2
Здравствуйте, C...R...a...S...H, Вы писали:

CRA>
    LightSynchronizer<int> sync = new LightSynchronizer<int>(this,
CRA>delegate
CRA>{
CRA>    return modifyDeviceGridSynch.VisibleDataRegion.Height;
CRA>}
CRA>

CRA>Какой интересно тип результата?

LightSynchronizer<int> sync

CRA>Следуя вашим рассуждениям данный код должне быть написан так:

CRA>
CRA>delegate
CRA>{
CRA>     int result = modifyDeviceGridSynch.VisibleDataRegion.Height;
CRA>     return result;
CRA>}
CRA>


Заставь дурака богу молиться, он и лоб расшибет (с) народная мудрость
Re[11]: LINQ как шаг к функциональному программированию
От: VladD2 Российская Империя www.nemerle.org
Дата: 22.01.09 07:14
Оценка: 1 (1) +1 :))
Здравствуйте, Undying, Вы писали:

U>LightSynchronizer<int> sync


А как их поиведенного кода можно узнать, что параметр типа — это именно возвращаемый тип делегата?

CRA>>Следуя вашим рассуждениям данный код должне быть написан так:

CRA>>
CRA>>delegate
CRA>>{
CRA>>     int result = modifyDeviceGridSynch.VisibleDataRegion.Height;
CRA>>     return result;
CRA>>}
CRA>>


U>Заставь дурака богу молиться, он и лоб расшибет (с) народная мудрость


Не знаю как на счет дураков. Но твой код надо писать уж тогда еще прикольнее:
delegate
{
  t1 x1 = modifyDeviceGridSynch;
  t2 x2 = x1.VisibleDataRegion;
  int result = x2.Height;
  return result;
}

Потому как типы всех промежуточных значений так же не известны из контекста.
Паранойя? Однозначно! Но это ваша, сударь, паранойя.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: LINQ как шаг к функциональному программированию
От: VladD2 Российская Империя www.nemerle.org
Дата: 22.01.09 07:20
Оценка: +1
Здравствуйте, MxKazan, Вы писали:

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

MK>Как это не нужна? А события?

А события нужно было реализовывать как список функциональных типов. Обычный List<T> решил бы проблему без каких-нибудь проблем. Более того, решение на базе явного списка получается гибче. Реализуя основанная на списке может сама управлять тем как обрабатывать возвращаемые значения отдельных "делегатов". Мултикаст-делегат же использует одну стратегию — игнорирования всех возвращаемых значений кроме одного. Та же ерунда и с возвращаемыми параметрами.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: LINQ как шаг к функциональному программированию
От: VladD2 Российская Империя www.nemerle.org
Дата: 22.01.09 07:29
Оценка:
Здравствуйте, SuhanovSergey, Вы писали:

SS>
var result = array1.Aggregate((first, second) => first + ", " + second);

SS>Это всё конечно изящно, но оно вылетает с исключением при пустой последовательности.

Есть такая беда. Кроме того код получается весьма не эффективным (циклическая конкатенация строк — плохое решение).
Так что на практике лучше использовать специализированную версию конкатенации. Это же просто примеры.
Задача статьи показать способы обработки данных, а не дать конкретные решения.
Лично я на практике пользуюсь макросом языка Nemerle ($"..$array1") который дает очень компактный синтаксис и максимально эффективное исполнение.

Кроме того нет проблем написать собственную версию Aggregate которая будет возвращать некоторое значение по умолчанию. Это же способ программирования, а не захардкоженая реализация одной функции!
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[12]: LINQ как шаг к функциональному программированию OFF-
От: VladD2 Российская Империя www.nemerle.org
Дата: 22.01.09 07:41
Оценка:
Здравствуйте, Undying, Вы писали:

H>>
H>>SimpleColumn(Caption : "Логин", CharWidth: 16, FontBold: true, BackColor: Color.MistyRose, ForeColor : Color.Black, FrozenColumn: true);
H>>


U>Такое решение неплохое, но у него есть два недостатка: 1) его нельзя расширить внешним образом, при добавлении нового параметра приходется вносить изменения в SimpleColumn


Что-то я не понял... А как же это можно расширить количество параметров и не вносить изменения в метод? Что без именованы параметров можно что-то менять ничего не меняя?

U>Сейчас на мой взгляд лучшее решение такое:


U>
U>           new SimpleColumn<RowLink>("Модель",
U>              delegate(RowLink device)
U>              {
U>                return modelBox.GetModel(Passport2.Model.GetValue(device));
U>              },
U>              GridExt.CharWidth(20), GridExt.HAlignment(true),
U>              GridExt.CellFiller(ComboGridCellFiller.Default),
U>              GridExt.ComboItems(modelBox.AllModels)),
U>


Здорово! Теперь задумайся сколько тут описано значений у которых отсутствует аннотация типа? Да почти все кроме параметра анонимного метода (device).
Напрашивается вопрос — как же этот пример демонстрирует твои идеи обязательной аннотации типов?

В данном примере типы неизвестны или частично неизвестны в 19 местах!!!
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: LINQ как шаг к функциональному программированию
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 22.01.09 07:53
Оценка:
Здравствуйте, Чистяков Влад (VladD2), Вы писали:

ЧВV>Статья:

ЧВV>LINQ как шаг к функциональному программированию
Автор(ы): Чистяков Влад (VladD2)
Дата: 26.01.2009
Цель данной статьи – объяснить читателю незнакомому с ФП, что такое функциональный подход, какие он дает преимущества, и как его можно использовать с помощью LINQ и C# 3.0.
Кроме того, эта статья дает некоторое понимание того, как работает «LONQ to Object» и на каких принципах он основан.


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


Функциональное вычисление – функция (или если быть точнее – «чистая функция», pure function) – должна принимать некоторые аргументы (входящие данные) на входе, производить вычисление и возвращать некоторый результат. При этом функция не должна создавать никаких побочных эффектов... В общем, функция не имеет право делать ничего, что могло бы изменить состояние чего бы то ни было. Все, что может сделать функция – это произвести вычисления и выдать результат.

У такого подхода есть одна замечательная особенность. Функция всегда должна возвращать один и тот же результат для одних и тех же аргументов.

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

ФЯ развивают эту идею, возводя ее в принцип – функция является в программе таким же полноценным объектом, как и экземпляр любого другого типа (например, экземпляр строки).

Сразу вопросы: можно ли функции сравнивать на равенство? Можно ли их сериализовать в файл? Вычислять хэш? Если нет, то не такие уж и полноценные объекты. Если да, возможно, стоит об этом упомянуть.

Скажем, в С мы можем передать указатель на функцию другой функции, но составить из двух функций третью мы не в силах.


typedef int (*func)(int);
int compose(func a, func b, int x)
{
    return a(b(x));
}



Первое, что требуется для манипуляции функциями – это иметь возможность описать их тип.

Неверно, если речь про ФЯ в целом. Как-то Лисп без этого обошелся.

И пара опечаток:

arg1 => arg2.ToString()

СПИСОК_ПОЛЕ_ПЕРЕЧИСЛЕННЫХ_ЧЕРЕЗ_ЗАПЯТУЮ

Re[10]: LINQ как шаг к функциональному программированию
От: Undying Россия  
Дата: 22.01.09 07:56
Оценка:
Здравствуйте, hugo, Вы писали:

U>>проще читается и модифицируется, нежели канонический:

H>Я, наверное, еще очень молодой, но ИМХО этот код не читается вообще .

Объясни почему такой код по-твоему читабелен:

      void CreateHeightModifyPanelSynchronizer()
      {
        LightSynchronizer<int> sync = new LightSynchronizer<int>(this,
          delegate
          {
            return modifyDeviceGridSynch.VisibleDataRegion.Height;
          },
          delegate (int visibleHeight)
          {
            int rowHeight = modifyDeviceGridSynch.RowHeight;
            modifyDevicePanel.Height = modifyDevicePanel.Height + (rowHeight - visibleHeight);
          },
          TimeSpan.FromMilliseconds(100));
      }
...
      CreateHeightModifyPanelSynchronizer();


а такой нет:

      if (true)
      {
        LightSynchronizer<int> heightModifyPanelSync = new LightSynchronizer<int>(this,
          delegate
          {
            return modifyDeviceGridSynch.VisibleDataRegion.Height;
          },
          delegate (int visibleHeight)
          {
            int rowHeight = modifyDeviceGridSynch.RowHeight;
            modifyDevicePanel.Height = modifyDevicePanel.Height + (rowHeight - visibleHeight);
          },
          TimeSpan.FromMilliseconds(100));
      }


Информация тут одна и та же, словесный смысл действия в первом варианте ты получаешь из названия метода, во втором из названия создаваемой переменной.

При этом чтение/модификация кода в первом случае сводится к постоянным Go To Definition и Ctrl+-, а во-втором случае для перемещения по коду достаточно колеса мыши.
Re[2]: LINQ как шаг к функциональному программированию
От: Undying Россия  
Дата: 22.01.09 08:07
Оценка: :)
Здравствуйте, SuhanovSergey, Вы писали:

SS>
var result = array1.Aggregate((first, second) => first + ", " + second);

SS>Это всё конечно изящно, но оно вылетает с исключением при пустой последовательности.

Перегрузка Aggregate((first, second) => first + ", " + second) вообще сомнительна, лучше всегда использовать:

array1.Aggregate("", (first, second) => first + ", " + second);


Здесь все прозрачно и может корректно работать на любой коллекции.
Re[11]: LINQ как шаг к функциональному программированию
От: hugo Австрия  
Дата: 22.01.09 09:11
Оценка: :)
Здравствуйте, Undying, Вы писали:

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


U>>>проще читается и модифицируется, нежели канонический:

H>>Я, наверное, еще очень молодой, но ИМХО этот код не читается вообще .

U>Объясни почему такой код по-твоему читабелен:


Я НИГДЕ НЕ писал, что такой код читабелен, будь внимателен, когда отвечаешь. Теперь я уже вообще не пойму, о чем ты говоришь .
Re[12]: LINQ как шаг к функциональному программированию
От: Undying Россия  
Дата: 22.01.09 09:19
Оценка: -1
Здравствуйте, hugo, Вы писали:

U>>Объясни почему такой код по-твоему читабелен:

H>Я НИГДЕ НЕ писал, что такой код читабелен, будь внимателен, когда отвечаешь. Теперь я уже вообще не пойму, о чем ты говоришь .

Я привел два варианта кода. В http://rsdn.ru/forum/message/3258359.1.aspx
Автор: hugo
Дата: 21.01.09
второй из вариантов ты поскипал, а по поводу первого варианта написал, что этот код нечитабелен. Это логично понять, как то, что второй вариант ты посчитал приемлимым. Если бы ты сразу написал, что оба варианта кода нечитабельны вопросов бы к тебе у меня не возникло.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.