На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! Правила раздела:
1. Название темы - краткое описание кто/что против кого/чего
2. В первом сообщении - список параметров, по которым идет сравнение.
3. Старайтесь аргументировать свои высказывания. Фразы типа "Венда/Слюникс - ацтой" считаются флудом.
4. Давайте жить дружно и не доводить обсуждение до маразма и личных оскорблений.
Модераторы: Модераторы, Комодераторы
Страницы: (3) [1] 2 3  все  ( Перейти к последнему сообщению )  
> Сломать шаблон , функциональный подход vs традиционный ООП
    Люди умеющие работать с функциональными ЯП, объясните, как сломать шаблон правильно представить в функциональной парадигме то, что раньше было ООП?
    Например класс содержащий какие-то там поля-свойства и методы. Как этот объект представляется в функциональных языках?
    Посмотрим на Erlang, педивикия пишет, что можно задействовать кортеж, но можно ли обратиться к элементам кортежа по именам полей?
    Как реализовать всякие методы? Делать кучу глобальных функций принимающих в качестве первого аргумента объект, как в старом добром C?
    Сообщение отредактировано: applegame -
      Цитата applegame @
      Делать кучу глобальных функций принимающих в качестве первого аргумента объект, как в старом добром C?
      объект с полями и указателями на методы, если совсем кратко
        Цитата SVK @
        объект с полями и указателями на методы, если совсем кратко
        И как создать такой объект? Можно простейший пример на том же Erlang?
          Цитата applegame @
          1) Люди умеющие работать с функциональными ЯП, объясните, как сломать шаблон правильно представить в функциональной парадигме то, что раньше было ООП?
          2) Например, класс содержащий какие-то там поля-свойства и методы.
          3) Как этот объект представляется в функциональных языках?
          4) Посмотрим на Erlang, педивикия пишет, что можно задействовать кортеж, но можно ли обратиться к элементам кортежа по именам полей?
          5) Как реализовать всякие методы? Делать кучу глобальных функций принимающих в качестве первого аргумента объект, как в старом добром C?

          1) В общем случае никак, это же другой подход, без объектов. В частных случаях — с помощью замыканий, например.
          2) Это не пример. Программирование существует не ради программирования, а объекты не ради объектов.
          3) См. пункт 1.
          4) У кортежа нет имён полей, не понимаю, о чём ты.
          5) См. пункт 1.

          Все ответы на твои вопросы есть в SICP:

          Lecture 6A

          Lecture 6B
          Сообщение отредактировано: korvin -
            Цитата SVK @
            Цитата applegame @
            Делать кучу глобальных функций принимающих в качестве первого аргумента объект, как в старом добром C?
            объект с полями и указателями на методы, если совсем кратко

            Ты функциональное программирование с процедурным не путаешь?
            Какие указатели в функциональном программировании?

            Добавлено
            applegame, может начать со scala/f#, просто оставить классы на какое-то время и посмотреть, к чему в итоге придёт проект?

            Добавлено
            Цитата applegame @
            Например класс содержащий какие-то там поля-свойства и методы. Как этот объект представляется в функциональных языках?

            В функциональных языках лучше это никак не представлять, а спроектировать другое решение исходной задачи.
              Цитата korvin @
              4) У кортежа нет имён полей, не понимаю, о чём ты.
              Это из педивикии, что-то я не так понял видимо:
              Цитата Wikipedia..Erlang.Кортеж
              В Erlang принято строить различные типы данных на основе кортежей с тегами, что облегчает отладку программы и считается хорошим стилем программировани
              Что такое кортеж, объяснять не нужно.
              Цитата korvin @
              1) В общем случае никак, это же другой подход, без объектов. В частных случаях — с помощью замыканий, например.

              Цитата D_KEY @
              В функциональных языках лучше это никак не представлять, а спроектировать другое решение исходной задачи.

              Я об этом, по сути, и спрашиваю. Смотришь на всякие учебники для новичков, а там туфта вроде подсчета чисел Фибоначчи, сортировки списков, всяких map/reduce, которые есть в любом современном языке и нихрена функциональному подходу не учат.
              Поэтому и говорю о ломании шаблона. Я при проектировании задачи сразу начинаю мыслить объектами. Как от этого уйти?
              Допустим простейший игровой сервер, где есть карта, есть NPC бродящие по этой карте и игроки. Ну вот как это спроектировать без ООП, ума не приложу?
              Ну карта - двумерный массив, а мобы и игроки?

              Добавлено
              Цитата D_KEY @
              Ты функциональное программирование с процедурным не путаешь?
              Какие указатели в функциональном программировании?
              Да, я тоже подумал что что-то недопонято. Я ковырял в свое время игровой сервер написанный целиком на C. Но там один хрен было ООП, как раз через поля структур в виде указателей. Там даже было наследование этих структур сымитировано через касты.
                D_KEY: да, попутал %)
                  Цитата korvin @
                  Все ответы на твои вопросы есть в SICP:
                  А на русском есть что-нибудь подобное. Я тяжело воспринимаю английский на слух.

                  Добавлено
                  Вот нашел первое попавшееся - http://www.youtube.com/watch?v=Ze6qdlyz-30 буду посмотреть.
                    Цитата applegame @
                    Цитата korvin @
                    Все ответы на твои вопросы есть в SICP:
                    А на русском есть что-нибудь подобное. Я тяжело воспринимаю английский на слух.

                    Ну книга SICP переведена на русский("структура и имплементация компьютерных программ"). Но я бы тебе ее рекомендовать не стал... Она слишком базовая. В MIT этот курс был для CS, а не SE.

                    Так что на счёт использования для начала функциональных языков, которые умеют ООП? Ocaml, F#, Scala. А там постепенно где видишь пользу от функционального программирования, там и используешь. Мне вообще кажется, что эти подходы вполне себе существуют вместе, на более высоком уровне у нас ОО-система, а на более детальном уровне функциональщина("конвейерная" работа с потоками данных, как можно меньше мутабельности, простое распараллеливание, сопоставление с образцом, алгебраические типы данных и пр.).

                    Добавлено
                    Цитата applegame @
                    Поэтому и говорю о ломании шаблона. Я при проектировании задачи сразу начинаю мыслить объектами. Как от этого уйти?
                    Допустим простейший игровой сервер, где есть карта, есть NPC бродящие по этой карте и игроки. Ну вот как это спроектировать без ООП, ума не приложу?

                    На последнем докладе о функциональщине, что я видел(вживую), докладчик рассматривал пример игры "жизнь". А потом спел песню про монады :D

                    Ссылку могу дать чуть позднее. Там на русском.

                    Добавлено
                    Agile Days 2015, Вагиф Абилов: А нам-то зачем функциональное программирование?
                    Цитата
                    В докладе на простых примерах дается представление о том, чем отличается моделирование предметной области и реализация функционала при использовании функциональных языков - таких, как F#, Scala и Clojure, в сравнении с объектно-ориентированными C# и Java. Какие типы задач наиболее подходят для функциональных языков? Как их лучше внедрять в проект? И как убедить руководство в практичности такого выборы? Обо всем этом пойдет речь в докладе.


                    Ну рассказал он не обо всем. Зато спел :)
                      Цитата applegame @
                      Это из педивикии, что-то я не так понял видимо:
                      Цитата Wikipedia..Erlang.Кортеж
                      В Erlang принято строить различные типы данных на основе кортежей с тегами, что облегчает отладку программы и считается хорошим стилем программировани
                      Что такое кортеж, объяснять не нужно.

                      А, кортеж с тэгами, это другое дело. По сути это записи (records) =)
                      Это уже зависит от конкретного языка, в Хаскелле, например, получить значения полей можно с помощью одноимённых функций-селекторов, которые автоматически генерируются при объявлении типа-записи. Не очень удобное решение, получается невозможно определить в одном модуле два типа-записи с одноимённым полем, будет конфликт имён. В Ocaml записи получше сделаны, ИМХО. Какой синтаксис в Erlang'е для работы с такими типами — ХЗ. Ну и конечно сопоставление с образцом (pattern matching), если у тебя не opaque-тип.

                      Цитата applegame @
                      Я об этом, по сути, и спрашиваю. Смотришь на всякие учебники для новичков, а там туфта вроде подсчета чисел Фибоначчи, сортировки списков, всяких map/reduce, которые есть в любом современном языке и нихрена функциональному подходу не учат.

                      Почитай Real World Haskell или Real World Ocaml (правда в Ocaml есть и классы с объектами, и сайд-эффекты можно использовать свободно, без контроля со стороны системы типов, поэтому Хаскелл в целом будет более нагляден).
                      Там более практичные примеры.

                      Цитата applegame @
                      Поэтому и говорю о ломании шаблона. Я при проектировании задачи сразу начинаю мыслить объектами. Как от этого уйти?
                      Допустим простейший игровой сервер, где есть карта, есть NPC бродящие по этой карте и игроки. Ну вот как это спроектировать без ООП, ума не приложу?
                      Ну карта - двумерный массив, а мобы и игроки?

                      Записи.
                      Сообщение отредактировано: korvin -
                        Цитата D_KEY @
                        Так что на счёт использования для начала функциональных языков, которые умеют ООП? Ocaml, F#, Scala. А там постепенно где видишь пользу от функционального программирования, там и используешь. Мне вообще кажется, что эти подходы вполне себе существуют вместе, на более высоком уровне у нас ОО-система, а на более детальном уровне функциональщина("конвейерная" работа с потоками данных, как можно меньше мутабельности, простое распараллеливание, сопоставление с образцом, алгебраические типы данных и пр.).

                        Agile Days 2015, Вагиф Абилов: А нам-то зачем функциональное программирование?
                        Цитата
                        В докладе на простых примерах дается представление о том, чем отличается моделирование предметной области и реализация функционала при использовании функциональных языков - таких, как F#, Scala и Clojure, в сравнении с объектно-ориентированными C# и Java. Какие типы задач наиболее подходят для функциональных языков? Как их лучше внедрять в проект? И как убедить руководство в практичности такого выборы? Обо всем этом пойдет речь в докладе.


                        Ну рассказал он не обо всем. Зато спел :)
                        Спасибо за ссылку, интересный и достаточно веселый доклад, хотя нового оттуда я мало чего почерпнул, скорее слегка углубил, то что уже знал. Кроме монад конечно. Я еще ими серьезно не занимался, а из доклада так и не понял разницу между исключениями и монадами. Также не совсем понял, что он там говорил об описании неких доменов. Это надо отдельно читать.
                        В качестве небольшого упражнения переписал F# код для игры Жизнь из лекции Абилова на D (фактически портирование):
                        Игра жизнь на D в функциональном стиле
                        ExpandedWrap disabled
                          import std.range;
                          import std.typecons;
                          import std.algorithm;
                          import std.functional;
                          import std.container;
                           
                          // возвращает список соседей клетки
                          auto neighbours(C)(C cell) {
                              return iota(-1,2)
                                  .map!(i => iota(-1,2)
                                      .map!(j => tuple(cell[0]+i, cell[1]+j)))
                                  .joiner
                                  .filter!(c => c != cell);
                          }
                           
                          // определяет жива ли клетка (клетка жива, если она есть в популяции)
                          bool isAlive(P, C)(P population, C cell) {
                              return population
                                  .canFind(cell);
                          }
                           
                          // возвращает список живых соседей клетки
                          auto aliveNeighbours(P, C)(P population, C cell) {
                              return cell
                                  .neighbours
                                  .filter!(curry!(isAlive, population));
                          }
                           
                          // определяет выживет ли клетка в следующей итерации
                          bool survives(P, C)(P population, C cell) {
                              return population
                                  .aliveNeighbours(cell)
                                  .walkLength.among(2, 3) > 0;
                          }
                           
                          // определяет родится ли клетка в следующей итерации
                          bool reproducible(P, C)(P population, C cell) {
                              return population
                                  .aliveNeighbours(cell)
                                  .walkLength == 3;
                          }
                           
                          // возвращает список всех "мертвых" соседей всех клеток популяции
                          auto allDeadNeighbours(P)(P population) {
                              return population
                                  .map!neighbours
                                  .joiner
                                  .make!RedBlackTree[]
                                  .filter!(not!(curry!(isAlive, population)));
                          }
                           
                          // возвращает следующее поколение популяции
                          auto nextGeneration(P)(P population) {
                              // соединяем списки всех выживших и родившихся клеток
                              return chain(
                                  population
                                      .filter!(curry!(survives, population)),
                                  population.allDeadNeighbours
                                      .filter!(curry!(reproducible, population))
                              );
                          }
                           
                          void main() {
                              import std.stdio;
                              import std.typecons;
                              immutable population = [tuple(-1,0), tuple(0,0), tuple(1,0)];
                              population.nextGeneration.writeln;
                          }

                        В целом, функциональным подходом на уровне вышеприведенного кода я и так активно пользуюсь в своих проектах, включая иммутабельность (как раз ради эффективного распараллеливания без синхронизации между потоками).
                        С игрой Жизнь все понятно, вычичление новой итерации - чистая функция. Получили на вход список, вернули новый список. Результат строго детерминирован от входных данных.
                        Но вот типа на Erlang пишут распределенные системы, веб-сервера и все такое. В веб-сервере запросы зачастую не могут быть чистыми функциями, например запись в БД - вполне себе сайд-эффект. Что-то мне подсказывает что тут-то и начинается расколбас с монадами. Это так?

                        Добавлено
                        Еще вот интересный момент: у Абилова в примере с игрой Жизнь, в функции создания списка соседей присутствуют циклы. Разве в труЪ функциональном подходе циклы в традиционном понимании используются?
                        Сообщение отредактировано: applegame -
                          Цитата applegame @
                          1) Но вот типа на Erlang пишут распределенные системы, веб-сервера и все такое. В веб-сервере запросы зачастую не могут быть чистыми функциями, например запись в БД - вполне себе сайд-эффект. Что-то мне подсказывает что тут-то и начинается расколбас с монадами. Это так?

                          2) Еще вот интересный момент: у Абилова в примере с игрой Жизнь, в функции создания списка соседей присутствуют циклы. Разве в труЪ функциональном подходе циклы в традиционном понимании используются?

                          1) Монады как бы не при чём. В Clean, нет монад, например, для сайд-эффектов используются unique types (или как-то так). Монада (в Хаскелле) — это всего лишь интерфейс, определяющий некоторые методы работы с данными. Если проводить аналогии с реальным миром, то это такая коробка, положив какой-то объект в которую, ты не можешь просто достать его, ты можешь только достать объект, что-то с ним сделать и положить в такую же коробку. Монада IO в этом плане несколько особенная, хотя язык не регламентирует её реализацию в исполнителе, но именно IO используется исполнителем, для реализации взаимодействия с внешним миром.

                          В Erlang'е монад нет, а интерфейс работы с БД может выглядеть и использоваться вполне себе функционально, ведь все сайд-эффекты как бы находятся во внешнем мире. «let (rows, err) = db.select(query, param...) in ...» — выглядит вполне себе функционально. «let err = db.exec("UPDATE ...", param...) in ...» тоже.

                          2) Не используются. Но синтаксис может позволять их выразить стандартными средствами, например forM_ в Хаскелле выглядит (и используется) как вполне себе цикл.

                          Добавлено
                          Вот тут, кстати, чел приводит пример, как в Хаскелле «реализуется ООП»: http://stackoverflow.com/questions/1310668...110560#13110560

                          Можешь ещё посмотреть на Functional Reactive Programming в Хаскелле, которое применяется для GUI, который обычно считается очень ООП-шной предметной областью.
                            Цитата korvin @
                            В Erlang'е монад нет, а интерфейс работы с БД может выглядеть и использоваться вполне себе функционально, ведь все сайд-эффекты как бы находятся во внешнем мире. «let (rows, err) = db.select(query, param...) in ...» — выглядит вполне себе функционально. «let err = db.exec("UPDATE ...", param...) in ...» тоже.
                            Да, но ведь такая функция получается не "чистая".

                            Ну хорошо. Прочитал вот тут про монаду состояния. Автор сэмулировал ее в жабаскрипте. Меня удивило, что ничего особенно сложного (по крайней мере в этом типе монад) я не заметил. Возможно я что-то тотально не понял и мне только показалось, что все понятно. И вот я сделал аналогичный код на D для того же стека на базе массива. Можно ли считать, что я сделал аналог монады состояния или все же, что-то было глобально не понято? Функции push и pop каррированы вручную, хотя в D для это есть бибилиотечная функция.
                            http://dpaste.dzfl.pl/bcf704330224
                            ExpandedWrap disabled
                              import std.stdio;
                               
                              auto push(int value) {
                                  return (const int[] stack) => stack ~ value;
                              }
                              auto pop() {
                                  return (const int[] stack) => stack.dup[0..$-1];
                              }
                               
                              auto monad(FS...)(FS funcs) if(funcs.length > 1) {
                                  return (const int[] stack) => monad(funcs[1..$])(funcs[0](stack));
                              }
                              auto monad(FS...)(FS funcs) if(funcs.length == 1) {
                                  return (const int[] stack) => funcs[0](stack);
                              }
                               
                              void main() {
                                  auto computation = monad(
                                      push(5),
                                      push(3),
                                      pop
                                  );
                                  computation([1, 2]).writeln;
                              }
                            Сообщение отредактировано: applegame -
                              Смотри как бы у тебя не развился D головного мозга ;) Все зачем-то на D переводишь. Это скорее вредно при попытках разобраться в чем-либо.
                              Сообщение отредактировано: D_KEY -
                                Цитата applegame @
                                1) Да, но ведь такая функция получается не "чистая".

                                2) Ну хорошо. Прочитал вот тут про монаду состояния. Автор сэмулировал ее в жабаскрипте. Меня удивило, что ничего особенно сложного (по крайней мере в этом типе монад) я не заметил. Возможно я что-то тотально не понял и мне только показалось, что все понятно. И вот я сделал аналогичный код на D для того же стека на базе массива. Можно ли считать, что я сделал аналог монады состояния или все же, что-то было глобально не понято? Функции push и pop каррированы вручную, хотя в D для это есть бибилиотечная функция.
                                http://dpaste.dzfl.pl/bcf704330224
                                ExpandedWrap disabled
                                  import std.stdio;
                                   
                                  auto push(int value) {
                                      return (const int[] stack) => stack ~ value;
                                  }
                                  auto pop() {
                                      return (const int[] stack) => stack.dup[0..$-1];
                                  }
                                   
                                  auto monad(FS...)(FS funcs) if(funcs.length > 1) {
                                      return (const int[] stack) => monad(funcs[1..$])(funcs[0](stack));
                                  }
                                  auto monad(FS...)(FS funcs) if(funcs.length == 1) {
                                      return (const int[] stack) => funcs[0](stack);
                                  }
                                   
                                  void main() {
                                      auto computation = monad(
                                          push(5),
                                          push(3),
                                          pop
                                      );
                                      computation([1, 2]).writeln;
                                  }

                                1) Она нечиста лишь потому, что нечиста БД, с точки зрения языка она относительно чиста, т.к. не позволяет изменять значения переменных. Ну в Хаскелле для того и существует IO, а в Эрланге с его динамической типизацией… Хз, возможно и можно было помечать все нечистые функции как-нибудь и сделать эту пометку «заразной», но зачем? Эрланг больше про взаимодействие процессов, чем функциональщину, а процессы выполняются параллельно, т.е. в любом случае получаем нечистую систему, просто описывается она языком в основном чистых функций. Так что Эрланг — далеко не самый удачный язык для знакомства с ФП, лучше взять Хаскелл, Clean, Miranda (последний, правда, давно мёртв).

                                2) Ты ничего не понял, я же написал, что Монада (в Хаскелле) — это просто интерфейс или абстрактный класс с парой методов (на самом деле там их вроде четыре, но обычно определяют два — return и (>>=), т.к. (=<<), (>>) и (<<) выражены через (>>=), а fail определяется автоматически или что-то в таком духе).

                                Т.е. на «традиционном ООП языке» Монада выглядит так:

                                ExpandedWrap disabled
                                  // Monad lib
                                   
                                  public interface Monad forall<A, B> {
                                      Monad<B> bind(M<B> proc(A));
                                  }
                                   
                                  // Monad IO lib
                                   
                                  import Monad;
                                   
                                  public class IO<A> : Monad forall<B> {
                                   
                                      private A value;
                                   
                                      // конструктор выполняет роль функции join (она же return в Хаскелльной Monad)
                                      public IO(A value) {
                                          this.value = value;
                                      }
                                   
                                      public IO<B> bind(IO<B> proc(A)) {
                                          return proc(this.value);
                                      }
                                  }
                                   
                                  // IO utilities lib
                                   
                                  import IO;
                                   
                                  public IO<Void> print(T value) {
                                      Console.WriteLine(value);
                                      return new IO<Void>();
                                  }
                                   
                                  public IO<T> read() {
                                      return new IO<T>(Console.Read<T>());
                                  }
                                   
                                  // Our code
                                   
                                  import IO, IOutil;
                                   
                                  Int inc(Int x) {
                                      return x + 1;
                                  }
                                   
                                  IO<Int> ioInc(Int x) {
                                      return new IO<Int>(x + 1);
                                  }
                                   
                                  Void main() {
                                      IO<Int> x = read<Int>();
                                      // теперь мы не можем просто взять и вытащить x из монады IO
                                      // и не можем использовать простую inc, только ioInc
                                      x
                                      .bind(ioInc)
                                      .bind(print);
                                      // важно то, что результатом любой манипуляции с IO-значением
                                      // является (другое или такое же) IO-значение, т.е.
                                      // монада как бы "заразна". Вот и всё.
                                  }

                                Это упрощённо, без ленивости.

                                Добавлено
                                Цитата applegame @
                                Автор сэмулировал ее в жабаскрипте.

                                Совершенно, абсолютно бесполезное занятие, особенно для объяснения, что такое монада. Автор вообще не понял, что это, смешал в кучу монаду, ST и ленивость. Зачем? Монада IO в JS, да и в (почти) любом императивном языке — это точка с запятой ( ; ), точнее это функция bind, именно она позволяет компилятору выстроить правильную последовательность действий в программе.
                                Сообщение отредактировано: korvin -
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:
                                Страницы: (3) [1] 2 3  все


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,1027 ]   [ 16 queries used ]   [ Generated: 19.04.24, 03:43 GMT ]