На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: ElcnU, ANDLL, fatalist
Страницы: (4) [1] 2 3 ... Последняя » все  ( Перейти к последнему сообщению )  
> Изучаю Haskell
    Здрасте!

    начал изучать Haskell :D
    вот пытаюсь перевести на JS код с Haskell но тока в функциональном стиле JS
    ExpandedWrap disabled
      nouns = ["frog","raven","ribbit"]
      adjectives = ["lazy","angry","tiny","happy","shy"]
      mixin nouns adjectives = [adj ++ " " ++ noun | adj <– adjectives, noun <– nouns]

    Выхлоп
    ExpandedWrap disabled
      [ "lazy frog","angry frog","tiny frog","happy frog","shy frog",
      "lazy raven","angry raven","tiny raven","happy raven","shy raven",
      "lazy ribbit","angry ribbit","tiny ribbit","happy ribbit","shy ribbit" ]


    Пробую через Array,reduce, пока стена :wall:
      Сам порешал :D
      ExpandedWrap disabled
        function mixin(nouns, adjs) {
            return nouns.reduce((a, noun) => {
              const v = adjs.map(adj => {
                return adj + ' ' + noun;
              });
              return [...a, ...v];
            }, []);
        }


      На хаскелле как то более проще думать такие задачи, лямбда исчисление рулит! :whistle:

      Haskell:
      ExpandedWrap disabled
        mixin nouns adjs = [adj ++ " " ++ noun | adj <– adjs, noun <– nouns]

      Так изменил в более функциональный стиль JS, но все равно не так очевидно как на Хаскеле :D
      ExpandedWrap disabled
        const mixin = (nouns, adjs) => nouns.reduce((a, noun) => [...a, ...adjs.map(adj => adj + ' ' + noun)], []);
      Сообщение отредактировано: Cfon -
        Продолжаю изучать удивительный Haskell! :D
        Еще одна задачка на поиск прямоугольных треугольников, дано три списка с числами от 1 до 10 например, надо найти все совпадения прямоугольных треугольников. На хаскеле изи! :D
        ExpandedWrap disabled
          aa =[1..10]
          bb = [1..10]
          cc = [1..10]
          triples aa bb cc = [(a,b,c) | a <- aa, b <- bb, c <- cc, a^2 + b^2 == c^2]

        Выхлоп
        ExpandedWrap disabled
          [(4,3,5),(3,4,5),(8,6,10),(6,8,10)]

        Как теперь это на JS написать? :wacko:

        Добавлено
        Переключил моск с функционального на императивный режим :lool:
        Оказывается тут идет тупой перебор по трем циклам :D
        ExpandedWrap disabled
          const aa = [1,2,3,4,5,6,7,8,9,10];
          const bb = [1,2,3,4,5,6,7,8,9,10];
          const cc = [1,2,3,4,5,6,7,8,9,10];
           
          function triples(aa, bb, cc) {
            var v=[];
            aa.forEach(a => {
              bb.forEach(b => {
                cc.forEach(c => {
                  if ((a*a + b*b) === c*c) {
                    v.push([a,b,c]);
                  }
                });
              });
            });
            return v;
          }
        Сообщение отредактировано: Cfon -
          Одно замечание по коду, в Хаскеле все функции автоматически каррируются :D
          на JS это будет выглядеть так
          ExpandedWrap disabled
            // Каррированная версия triples
            function triples(aa) {
              return bb => {
                return cc => {
                  var v = [];
                  aa.forEach(a => {
                    bb.forEach(b => {
                      cc.forEach(c => {
                        if ((a*a + b*b) === c*c) {
                          v.push([a,b,c]);
                        }
                      });
                    });
                  });
                  return v;
                };
              };
            }
             
            triples(aa)(bb)(cc);

          зачем Хаскель это делает? :blink:
          да хз я еще не дошел до этого... вроде бы это связано с его реализацией, а именно лямбда функциями :unsure:
          в данном коде на JS это делать не обязательно :D
          Сообщение отредактировано: Cfon -
            Разобрался зачем :D
            Для того чтобы юзать их в функциях высшего порядка, например
            ExpandedWrap disabled
              const result = [[1,2,3,4,5],[6,7,8,9,10]].map(triples(aa)(bb));
              console.log(result);
              // [[[ 3, 4, 5 ]], [[ 6, 8, 10 ]]]


            ну а на Haskell все проще :D
            ExpandedWrap disabled
              map (triples aa bb) [[1..5],[6..10]]
              // [[(3,4,5)],[(6,8,10)]]


            Кто не понял объясняю, каррированная функция передается функции высшего порядка путем частичного применения :blush:

            Добавлено
            Очередной вопрос, вот на Haskell код так называемой быстрой сортировки
            ExpandedWrap disabled
              quicksort [] = []
              quicksort (x : xs) =
                  quicksort [a | a <- xs, a <= x] ++
                  [x] ++
                  quicksort [a | a <- xs, a > x]


            как его переделать на JS :wacko:
            Сообщение отредактировано: Cfon -
              Вот вам функционально-подобная попытка на JS приблизится к великому Хаскеллу :D
              ExpandedWrap disabled
                function quicksort(array) {
                    if (array.length === 0) return [];
                    
                    const origin = [...array];
                    const elem0 = origin.pop();
                    const left = origin.filter(elem => elem < elem0);
                    const right = origin.filter(elem => elem >= elem0);
                 
                    return [...quicksort(left), elem0, ...quicksort(right)];
                }
                 
                var nums = [10,2,5,3,1,6,7,4,2,3,4,8,9];
                var sortedNums = quicksort(nums);
                console.log(nuts);       // [ 10, 2, 5, 3, 1, 6, 7, 4, 2, 3, 4, 8, 9 ]
                console.log(sortedNums); // [ 1, 2, 2, 3, 3, 4, 4, 5, 6, 7, 8, 9, 10 ]


              И все равно императивный стиль JS присутствует :D
              Сообщение отредактировано: Cfon -
                Для евангелистов reduce коим являюсь сам :D, вот более оптимизированая версия за счет одного цикла, вместо двух в случае с filter:
                ExpandedWrap disabled
                  function quicksort(array) {
                      if (array.length === 0) return [];
                      
                      const origin = [...array];
                      const elem0 = origin.pop();
                   
                      var res = origin.reduce((aa, elem) => (
                          (elem < elem0)
                              ? [[...aa[0], elem], aa[1]]
                              : [aa[0], [...aa[1], elem]]
                      ), [[],[]]);
                      
                      return [...quicksort(res[0]), elem0, ...quicksort(res[1])];
                  }

                Цикла? :facepalm:
                Да-да не удивляйтесь! В JS все равно надо переключаться в императивный режим :jokingly:
                Сообщение отредактировано: Cfon -
                  Продолжаю переносить задачки из Хаскель на JS :D

                  вот исходная задачка на удаление определенного числа элементов из списка с использованием рекусии:
                  ExpandedWrap disabled
                    drop 0 xs = xs
                    drop _ [] = []
                    drop n (x:xs) = drop (n-1) xs

                  а вот та же но через foldl (это аналог reduce в JS)
                  ExpandedWrap disabled
                    drop 0 xs = xs
                    drop _ [] = []
                    drop n xs = foldl (\xs _ -> tail xs) xs [1..n]

                  С рекурсией на JS не было проблем
                  ExpandedWrap disabled
                    function drop(n, array) {
                        if (n === 0) return array;
                        if (array.length == 0) return [];
                        
                        array.shift();
                        return drop(n-1, array);
                    }
                     
                    drop(1, [1,2,3]) // [2,3]

                  а вот как сделать тоже но через reduce? :wacko:

                  Небольшая поправочка в Хаскелле все данные иммутабельны, а у меня тут исходный массив array меняется, что не в Хаскел-стиле! Правим:
                  ExpandedWrap disabled
                    function drop(n, array) {
                        const origin = [...array];
                        if (n === 0) return origin;
                        if (array.length == 0) return [];
                        
                        origin.shift();
                        return drop(n-1, origin);
                    }
                  Сообщение отредактировано: Cfon -
                    :lool: ВСЕ ПРОСТО!! я забыл что в JS можно изменять состояние, это ж не Хаскель :facepalm:
                    Мде сложно переключаться с функционального на императивный режим, надо тернироваться :D
                    Вот решение, получается еще проще чем в Хаскелле
                    ExpandedWrap disabled
                      function drop(n, array) {
                          if (n === 0) return array;
                          if (array.length == 0) return [];
                       
                          return array.reduce((accum, elem) =>
                              (n-- > 0) ? accum : [...accum, elem], //<--- ВОТ ТУТ ИЗМЕНЯЕМ n.
                          []);
                      }

                    или через filter еще проще :D
                    ExpandedWrap disabled
                      function drop(n, array) {
                          if (n === 0) return array;
                          if (array.length == 0) return [];
                          
                          return array.filter(() => (n-- <= 0));
                      }

                    да и начальные условия тут тоже можно опустить :D
                    ExpandedWrap disabled
                      function drop(n, array) {  
                          return array.filter(() => (n-- <= 0));
                      }


                    Хотя я погорячился сказав что проще Хаскеля не проще! куда ж еще проще? :blink:
                    ExpandedWrap disabled
                      drop n xs = foldl (\(_:xs) _ -> xs) xs [1..n]


                    Да в JS уже есть функция удаления splice, но моя цель перевести с Haskell на JS в функциональном стиле, хотя в предыдущих вариантах был применен полу императивный стиль, а не фунциональный и решение в Haskell стиле требует еще покумекать :scratch:
                    ну т.е. сделать без мутации переменной n.
                    Сообщение отредактировано: Cfon -
                      Так так так... ща рожу... а не показалось :lool:
                        .... иииии! родил зверюшку! :lool:
                        ExpandedWrap disabled
                          function drop(n, array) {
                              const v = [...Array(n)].map((_,n) => n + 1);
                              return v.reduce(xs => {
                                  xs.shift();
                                  return xs;
                              }, [...array]);
                          }

                        Объясняю что тут происходит. Я не сразу допедрил как можно это решить без мутации n! :wall:
                        Сила императивного стиля моск реально морозит :D но после долгих насилований себя я прозрел! :jokingly:

                        если внимательно посмотреть на код Хаскелля видно что он просто производит свертку по числовому списку, а не по целевому списку! Вот где фокус то был! :blink:
                        Ну а дальше дело техники, генерирую массив чисел от 1 до n поскольку в JS нет встроенного генератора массива как в Хаскелле и далее делаю свертку хотя это на самом деле не свертка, а простая мутация исходного массива путем выкидывания лишних элементов :D
                        Все тоже можно было сделать тупо в цикле, но мне хотелось приблизить код к Хаскел-стилю, ну те. к функциональному стилю :blush:

                        Немного видоизменил код чтобы максимально приблизится к Haskell:
                        ExpandedWrap disabled
                          const genN = n => [...Array(n).map((_, n) => n + 1)];
                          const drop = (n, xs) => genN(n).reduce(xs => (xs.shift(), xs), [...xs]);

                        Вроде бы уже похоже на функциональный стиль :D
                        Сообщение отредактировано: Cfon -
                          Реализация drop через свертку исходного списка
                          ExpandedWrap disabled
                            drop n xs = fst $ foldr f z xs
                              where
                                f x (xs, m) | m > 0 = (x:xs, m-1)
                                f _ (xs, _) = (xs,0)
                                z = ([], m)
                                m = length xs - n

                          получилось длиннее, но более понятно :D

                          теперь надо перевести на JS :blink:

                          OK. будем думать.

                          ПС. в последнее время я стал адептом краткой нотации :D
                          Сообщение отредактировано: Cfon -
                            Готово! Максимально приближенный Хаскель-стиль :blush:
                            ExpandedWrap disabled
                              const drop = (n, xs) => (
                                  xs.reduceRight(({xs, m}, x) => (
                                      (m > 0) ? (xs.unshift(x), {xs, m: m-1}) : {xs, m:0}
                                  ), {xs:[], m: xs.length - n}).xs
                              );

                            Нравится мне эта шифрограмма! :D
                              Продолжаем, на очереди dropWhile, его суть отсечение элементов списка по условию. Пока условие истина элементы выкидываются, как только условие ложно все остальные элементы включаются в список:
                              ExpandedWrap disabled
                                dropWhile p xs = fst $ foldl f z xs
                                  where
                                    f (xs, b) x | b && p x = (xs, True)
                                    f (xs, _) x = (xs ++ [x], False)
                                    z = ([], True)
                                 
                                dropWhile (>3) [4,1,2,3,4,5] // [1,2,3,4,5]

                              p - предикат, xs - список
                              Надо преложить на JS. Думаем! :hang:
                              Хотя пока думаю один я :D
                              Сообщение отредактировано: Cfon -
                                Решил по аналогии с drop! :D
                                ExpandedWrap disabled
                                  const dropWhile = (p, xs) => (
                                      xs.reduce(({xs, b}, x) =>
                                          (b && p(x)) ? {xs, b:true} : {xs:[...xs, x], b:false},
                                      {xs:[], b:true}).xs
                                  );
                                   
                                  dropWhile(x => x > 3, [4,1,2,3,4,5] // [1,2,3,4,5]

                                немного были затыки с анонимной функцией, а так изи :D

                                Переменную b в JS можно не передавать в акумуляторном объекте, его можно мутировать в замыкании, тут я просто перенес один в один решение в Хаскелл-стиле где нельзя менять значения переменных :blush:

                                Например вот как будет в императивном стиле JS
                                ExpandedWrap disabled
                                  const dropWhile = (p, xs) => {
                                      var b = true; //исходное состояние
                                      return xs.reduce((xs, x) =>
                                          (b && p(x)) ? xs : (b = false, [...xs, x]),
                                                          //  ^^ изменяем состояние
                                      [])
                                  };

                                как видите код в немного сократился, за счет выкидывания b из аккумуляторного объекта и замены его простым массивом.

                                Первые впечатления от Хаскелла в основном положительные :good:
                                Функциональный стиль, строгая типизация и т.д все классно,
                                но если сравнивать с моим кодингом на JS, на Хаскелл сложнее отлаживать хотя он и строго типизирован, но вот мессажи об ошибках, которые возникаю при компиляции, вгоняют меня в ступор, например
                                ExpandedWrap disabled
                                  hof.hs:81:15: error:
                                      * Couldn't match expected type `[a1]'
                                                    with actual type `([a1], Bool)'
                                      * In the first argument of `(++)', namely `xs'
                                        In the expression: xs ++ [x]
                                        In the expression: (xs ++ [x], False)
                                      * Relevant bindings include
                                          x :: a1 (bound at hof.hs:81:10)
                                          xs :: ([a1], Bool) (bound at hof.hs:81:7)
                                          f :: ([a1], Bool) -> a1 -> ([a1], Bool) (bound at hof.hs:80:5)

                                :wacko:

                                да на JS было много ошибок в рантайме, но хз я их изи правил и находил, чего не скажу пока про Хаскелл :wall:
                                думаю если научусь их читать, то ваще будет шоколадно :D

                                Рекомендую ли я Haskell к изучению новичкам в программировании? Скорее нет, чем да :D
                                а вот тем кто уже мастер императивном программинге, то велком в Хаскелл найдете много интересного! И мозоль в мозге первое время будет большая :D
                                Эт я еще монады не трогал и не прогал GUI, БД и тп, знающие прогеры ну те кто круче меня :D пугают меня ими :lool:
                                Сообщение отредактировано: Cfon -
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,0681 ]   [ 16 queries used ]   [ Generated: 16.04.24, 04:32 GMT ]