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

    ExpandedWrap disabled
      import Control.Monad
       
      foo n = do
          i <- [1..n]
          j <- [i..n]
          k <- [j..n]
          return (i, j, k)
       
      bar n = [ (i, j, k) | i <- [1..n], j <- [i..n], k <- [j..n] ]
       
      baz n = concat $ concat $
          map (\i -> map (\j -> map (\k -> (i, j, k))
                                    [j..n])
                         [i..n])
              [1..n]
       
      main = let n = 3 in
          forM_ [foo, bar, baz] $ \f ->
              print $ f n


    ExpandedWrap disabled
      [(1,1,1),(1,1,2),(1,1,3),(1,2,2),(1,2,3),(1,3,3),(2,2,2),(2,2,3),(2,3,3),(3,3,3)]
      [(1,1,1),(1,1,2),(1,1,3),(1,2,2),(1,2,3),(1,3,3),(2,2,2),(2,2,3),(2,3,3),(3,3,3)]
      [(1,1,1),(1,1,2),(1,1,3),(1,2,2),(1,2,3),(1,3,3),(2,2,2),(2,2,3),(2,3,3),(3,3,3)]

    http://ideone.com/E21ZDr

    Как нетрудно заметить, функции foo, bar и baz абсолютно идентичны по результату и отличаются лишь во внешнем виде исходного кода. foo реализована с помощью do-нотации благодаря Monad [].

    https://www.fpcomplete.com/school/starting-...-the-list-monad
    http://en.wikibooks.org/wiki/Haskell/Under...ing_monads/List
      Цитата D_KEY @
      Смотри как бы у тебя не развился D головного мозга ;)
      Уже развился до терминальной стадии. :D Но это не ослепляет меня. В D полно говна, но пока это лучшее, из того, что у меня есть.
      Цитата D_KEY @
      Все зачем-то на D переводишь. Это скорее вредно при попытках разобраться в чем-либо.
      На D потому что в данный момент это язык, которым я владею намного лучше остальных языков. Я мог бы ваять примеры на Ruby или плюсах, но это заняло бы гораздо больше времени.
      Цитата korvin @
      Совершенно, абсолютно бесполезное занятие, особенно для объяснения, что такое монада. Автор вообще не понял, что это, смешал в кучу монаду, ST и ленивость. Зачем? Монада IO в JS, да и в (почти) любом императивном языке — это точка с запятой ( ; ), точнее это функция bind, именно она позволяет компилятору выстроить правильную последовательность действий в программе.

      Насчет точки с запятой - очень хорошая аналогия. помогла мне кое-что осознать. С точки зрения функционального программирования не существует алгоритма, как некоей последовательности действий. Это, ИМХО, крайне важный момент, которому, я считаю, уделяют слишком мало внимания в лекциях и учебниках. Сама природа человека строит все на цепочках событий, а тут надо забыть про это. Есть исходный материал, а есть множество функций от этого материала и множество результатов этих функций. Причем и материалы и результаты также могут быть функциямии. Все это происходит вне времени. Время конечно может участвовать как агрумент функций, но сами функции "плавают" в некоем безвременном "гиперпространстве".
      Суть монады, насколько я понял, как раз в формализации последовательности из двух вычислений. При этом значения аргумента и результата обернуты в монаду, а результат первого вычисления является аргументом второго вычисления.
      Своим "примером" монады, я скорее сымитировал один из вариантов реализации внутренностей монады, а не саму монаду.
        Цитата applegame @
        Насчет точки с запятой - очень хорошая аналогия. помогла мне кое-что осознать. С точки зрения функционального программирования не существует алгоритма, как некоей последовательности действий. Это, ИМХО, крайне важный момент, которому, я считаю, уделяют слишком мало внимания в лекциях и учебниках. Сама природа человека строит все на цепочках событий, а тут надо забыть про это. Есть исходный материал, а есть множество функций от этого материала и множество результатов этих функций. Причем и материалы и результаты также могут быть функциямии. Все это происходит вне времени. Время конечно может участвовать как агрумент функций, но сами функции "плавают" в некоем безвременном "гиперпространстве".

        Суть монады, насколько я понял, как раз в формализации последовательности из двух вычислений. При этом значения аргумента и результата обернуты в монаду, а результат первого вычисления является аргументом второго вычисления.
        Своим "примером" монады, я скорее сымитировал один из вариантов реализации внутренностей монады, а не саму монаду.

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

        А суть монады ты неправильно понял, как и тот автор, я ж написал пример на предыдущей странице. У монады нет никаких внутренностей, это интерфейс.
          Цитата korvin @
          Это всё пустые философствования. Ты не можешь вернуться в прошлое, например, таким образом пространство-время — это просто поток, ленивый список моментов, вычисляющийся по мере необходимости (течении времени), преобразование одного момента в другой — чистая функция. Но что толку от всех этих аналогий?
          Философствования - да. Пустые ли они? Не уверен. Для проектирования задачи важно понимание. Перестать мыслить в рамках последовательности действий и начать мыслить в рамках функциональных трансформаций. Фиг его знает, мне помогает.
          Цитата korvin @
          А суть монады ты неправильно понял, как и тот автор, я ж написал пример на предыдущей странице. У монады нет никаких внутренностей, это интерфейс.
          Странно. У абстрактной монады, конечно, нет никаких внутренностей, но как же конкретные реализации вроде монады Maybe? Разве у нее нет внутренностей? Даже в твоем примере у класса IO<A> вполне есть "внутренности": join и bind.
          Сообщение отредактировано: applegame -
            Цитата applegame @
            Странно. У абстрактной монады, конечно, нет никаких внутренностей, но как же конкретные реализации вроде монады Maybe? Разве у нее нет внутренностей? Даже в твоем примере у класса IO<A> вполне есть "внутренности": join и bind.

            Странно, у интерфейса Monad, конечно, нет никаких внутренностей, но как же конкретные реализации вроде класса IO? Разве у класса нет внутренностей?

            Я не понимаю, в чём твоя проблема, в этом вашем D нет интерфейсов и классов?
              Цитата korvin @
              Я не понимаю, в чём твоя проблема, в этом вашем D нет интерфейсов и классов?
              Проблем никаких нет. Ответ ты и сам знаешь.
                Попрбовал Haskell и OCaml.
                Первый кошерен, второй мерзок.
                Кому пришла в голову бредовая идея делать отдельные математические операторы для int и float? Разделение элементов списка точками с запятой? Фу короче.
                А вот Хаскель - приятная штука.
                Сообщение отредактировано: applegame -
                  В хаскеле проблема ad-hoc полиморфизма просто решена здраво через type class'ы. В ocaml так просто не сделаешь, потому и отдельные операции там, где это важно с точки зрения типизации. Вместо ocaml можешь попробовать F#, это почти тот же язык, только причесанный и с многими дополнительными плюшками.
                    Цитата D_KEY @
                    Вместо ocaml можешь попробовать F#, это почти тот же язык, только причесанный и с многими дополнительными плюшками.
                    Он неплох, я уже немного видел его в приведеном тобой ролике с песней о монадах. Если бы не его привязанность к .NET, может быть и поковырялся бы с ним.
                    Пока поизучаю Haskell, тем более что многие вещи оказались знакомы по D (D_LANG гойловного мозга налицо). Например, бесконечные ленивые списки == бесконечные ленивые ranges.
                    Сообщение отредактировано: applegame -
                      Цитата applegame @
                      1) Кому пришла в голову бредовая идея делать отдельные математические операторы для int и float?

                      2) Разделение элементов списка точками с запятой? Фу короче.

                      3) А вот Хаскель - приятная штука.

                      1) Тому, кто придумал строгую типизацию и вывод типов. ML был придуман в 70-х, когда Хаскелла с его тайпклассами даже в проекте не было. ML полностью отрицает неявное приведение типов.

                      2) Вкусовщина. Мне не нравится, что имена типов пишутся со строчной буквы и странные правила использования двойной точки-с-запятой, но это такая мелочь.

                      3) Да, но мне интересно, что ты скажешь, когда познакомишься с ним получше и узнаешь, что, например, написав хвостово-рекурсивную функцию внезапно обнаружишь переполнение стека, из-за ленивости, и окажется, что нужно форсировать вычисления специальным образом. Или то, что ты не можешь просто взять и вставить в середину функции отладочную печать, т.к. IO заразна и тебе придётся менять тип своей чистой функции на (IO T) (а то и переписывать её полностью). Несомненно, в дефолтной всеобщей ленивости и заразном IO есть свои плюсы, но зачастую это слегка непрактично.

                      Да и Функторы Ocaml немного удобней, понятней и проще в использовании, чем тайпклассы Хаскелла. + Если ты захочешь нормальный и удобный «динамический полиморфизм», ты скорее всего поменяешь своё мнение в пользу Ocaml.

                      Ну или F#, да, хотя, несмотря на некоторые весьма годные улучшения по сравнению с Ocaml, вроде есть и минусы. Если не ошибаюсь, модули например в F# примитивней Ocaml'овских.

                      Я поначалу Ocaml как-то тоже недолюбливал после Хаскелла, но потом, чем больше знакомился с ним, тем больше он мне стал нравиться (не в ущерб Хаскеллу, конечно =)).

                      Добавлено
                      Цитата applegame @
                      Например, бесконечные ленивые списки == бесконечные ленивые ranges.

                      Гм… А как будет на D'шных рейнджах выглядеть такой код:

                      ExpandedWrap disabled
                        fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
                         
                        main = print $ take 10 fibs

                      ExpandedWrap disabled
                        [0,1,1,2,3,5,8,13,21,34]


                      В Хаскелле ленивы не только списки, он ленив весь.
                      Сообщение отредактировано: korvin -
                        Цитата korvin @
                        Или то, что ты не можешь просто взять и вставить в середину функции отладочную печать, т.к. IO заразна и тебе придётся менять тип своей чистой функции на (IO T) (а то и переписывать её полностью).

                        А разве там нет специального костыля с unsafePerformIO как раз для дебажного принта?

                        Цитата korvin @
                        Гм… А как будет на D'шных рейнджах выглядеть такой код:

                        Ну в расте fibs будет возвращать итератор. Подозреваю, что рейнжи в D работают точно так же.
                        Сообщение отредактировано: DarkEld3r -
                          Цитата korvin @

                          Гм… А как будет на D'шных рейнджах выглядеть такой код:

                          ExpandedWrap disabled
                            fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
                             
                            main = print $ take 10 fibs

                          ExpandedWrap disabled
                            [0,1,1,2,3,5,8,13,21,34]


                          Аналогичный бесконечный ленивый рендж для чисел Фибоначчи можно сделать вот так:
                          ExpandedWrap disabled
                            import std.range;
                            import std.stdio;
                             
                            void main() {
                                auto fibs = recurrence!((a, n) => a[n-1] + a[n-2])(0, 1);
                                writeln(fibs.take(10));
                            }

                          ExpandedWrap disabled
                            (a,n) => a[n-1] + a[n-2] // лямбда вычисляющая очередное число
                            (0, 1)                   // первые два числа Фибоначчи

                          Результат - http://dpaste.dzfl.pl/9850c213f69a
                          Цитата korvin @
                          В Хаскелле ленивы не только списки, он ленив весь.

                          D по умолчанию не ленив, но ленивость можно указать явно:
                          ExpandedWrap disabled
                            import std.stdio;
                             
                            int foo() {
                                writefln("foo");
                                return 5;
                            }
                             
                            void bar(bool flag, lazy int data) { // аргумент data - ленивый
                                writefln("flag = %s", flag);
                                if(flag) writefln("data = %s", data);
                            }
                             
                            void main() {
                                bar(true, foo());
                                bar(false, foo());
                            }

                          ExpandedWrap disabled
                            flag = true
                            foo
                            data = 5
                            flag = false
                            Цитата DarkEld3r @
                            1) А разве там нет специального костыля с unsafePerformIO как раз для дебажного принта?

                            2) Ну в расте fibs будет возвращать итератор. Подозреваю, что рейнжи в D работают точно так же.

                            1) Есть такое выражение: «если вы используете UnsafePreformIO, то вам не нужен Haskell» или как-то так.

                            2) Я жду код, а не рассуждения.

                            Добавлено
                            Цитата applegame @
                            D по умолчанию не ленив, но ленивость можно указать явно:
                            ExpandedWrap disabled
                              import std.stdio;
                               
                              int foo() {
                                  writefln("foo");
                                  return 5;
                              }
                               
                              void bar(bool flag, lazy int data) { // аргумент data - ленивый
                                  writefln("flag = %s", flag);
                                  if(flag) writefln("data = %s", data);
                              }
                               
                              void main() {
                                  bar(true, foo());
                                  bar(false, foo());
                              }

                            ExpandedWrap disabled
                              flag = true
                              foo
                              data = 5
                              flag = false

                            Тут-то D и сел в лужу. Ибо сочетать ленивость и сайд-эффекты — это не в тапки гадить.

                            http://ideone.com/A0pXvm

                            ExpandedWrap disabled
                              foo = do
                                  putStrLn "foo"
                                  return 5
                               
                              bar flag d = do
                                  putStrLn $ "flag = " ++ show flag
                                  x <- d
                                  if flag
                                      then putStrLn $ "data = " ++ show x
                                      else return ()
                               
                              main = do
                                  bar True  foo
                                  bar False foo


                            ExpandedWrap disabled
                              flag = True
                              foo
                              data = 5
                              flag = False
                              foo
                              korvin, раскрой мысль. Не очень понял, почему второй раз правильно вызывать foo. В чем фейл D?

                              Добавлено
                              И вообще, если ты сделаешь x <- d внутри if'а, то будет так же, как в D :-?
                              Сообщение отредактировано: D_KEY -
                                Цитата korvin @
                                Тут-то D и сел в лужу. Ибо сочетать ленивость и сайд-эффекты — это не в тапки гадить.
                                Твой код не эквивалентен моему.
                                Цитата D_KEY @
                                И вообще, если ты сделаешь x <- d внутри if'а, то будет так же, как в D
                                Ага, korvin смухлевал. :D
                                Вот как должно было быть:
                                http://ideone.com/GO7ZhH
                                ExpandedWrap disabled
                                  foo = do
                                      putStrLn "foo"
                                      return 5
                                   
                                  bar flag d = do
                                      putStrLn $ "flag = " ++ show flag
                                      if flag
                                          then do
                                              x <- d
                                              putStrLn $ "data = " ++ show x
                                          else return ()
                                   
                                  main = do
                                      bar True  foo
                                      bar False foo

                                ExpandedWrap disabled
                                  flag = True
                                  foo
                                  data = 5
                                  flag = False
                                Сообщение отредактировано: applegame -
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:
                                Страницы: (3) 1 [2] 3  все


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,0616 ]   [ 16 queries used ]   [ Generated: 24.04.24, 12:19 GMT ]