1. Куча / Говнокод #12620

    +124

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    16. 16
    17. 17
    18. 18
    19. 19
    20. 20
    21. 21
    22. 22
    23. 23
    24. 24
    25. 25
    import Control.Monad
    import Control.Arrow
    import Data.List
    
    solve' :: [String] -> [[String]]
    solve' = nub . filter (
                and . uncurry (
                    zipWith (
                        (.head) . (==) . last
                    )
                ) . (id &&& tail)
             ) . uncurry ($) . (
                last . (((
                    map (
                        last . fst &&& uncurry (++) . (init . fst &&& snd)
                    ) . tail . uncurry (zipWith (,)) . (inits &&& tails)
                ) >=> (uncurry map) . 
                    ((:) *** solve')
                ):
                ) . (uncurry takeWhile) . (
                        const . null &&& const [const [[]]]
                    ) &&& id
             )
    
    main = print $ solve' ["123","321","123"]

    Запостил: HaskellGovno, 20 Февраля 2013

    Комментарии (24) RSS

    • хаскель? туториалы не врали: такой читабельный и интуитивный язык!
      Ответить
      • Да в приницпе форматирование хорошее и оно читабельно.
        Кресты тоже эзотерика, до тех пор пока значки не выучишь. Тут та же проблема - аинтуитивность обозначений.
        Кстати я заметил что тут многие любители С++ изучили и хацкиль. Повторюсь: тут очень кошерно отформатирован код, даже местами прослеживается следование заветам тарасоформатирования.

        > nub . filter
        Ответить
        • > nub . filter
          Очень даже неплохой. Меня отфильтровал, т.к. я не знаю, что делают >=> , &&& и ***. А читать про них что-то влом.
          Ответить
          • Апликативные функторы, а именно Kleisli стрелки?
            Ответить
            • Функциональное программирование — это: типы как объекты, каррированные функции как стрелки, HOFs как экспоненциалы, чистота, ссылочная прозрачность, аппликативность и свободные (при совпадении доменов-кодоменов) композиции, equational theory settings / reasoning как следствие, в терминах ТК, в том числе, начальные алгебры / финальные ко-алгебры как фреймворк для описания индуктивных рекурсивных данных (как выход - результаты, значения) и ко-индуктивных ко-рекурсивных потоков данных (как вход); функторы, монады, Kleisli категории - многие индуктивные [возможно] рекурсивные типы данных которые функторы (начиная с Identity, Maybe и List), также, обычные суммы, произведения и степени, то есть кортежи/записи, объединения/варианты и функции - writer, error и reader/environment, для функций более специального вида - prompt, parser, state и cont, par/conc/async как cont для fork/join/io/done языка; функторы, ко-монады, coKleisli категории - ко-индуктивные ко-рекурсивные типы данных которые функторы (простейшие потоки и деревья, например), те же произведения и степени (суммы?), указатели и изменяемые подструктуры (линзы, как функции в), зипперы; свободные монады вокруг типов данных которые функторы - iteratees (которые сами по себе потоки, то есть финальные коалгебры для соответвующих (строго-позитивных таки) функторов), разные языки (eDSL на ADT) и их интерпретаторы; ко-свободные ко-монады для типов данных которые функторы - ?;
              Ответить
              • (под)категории и стрелки - линзы (категория, тензор, но не вполне стрелка), обычные функции, Kleisli стрелки, coKleisli стрелки, стрелки biKleisli категорий, функции ограниченные типом - списки-в-списки, потоки-в-потоки, деревья-в-деревья, сигналы-в-сигналы и поведения-в-поведения (как оно применяется в FRP) и т.п., автоматы, симуляции, преобразователи, некоторые языки-eDSL-на-ADT, опять же; монадические трансформеры как определённого вида натуральные трансформации для определённого вида функторов над разными монадами - WriterT, ErrorT, ReaderT, StateT, ContT, MaybeT, ListT и т.д., например, ReaderT (ConstEnvironment, MutableScope, Resources) IO - эффекты, injectable read-only / write окружение, список ресурсов пополняемый их захватами по мере выполнения и автоматически освобождаемый в конце; полугруппы, моноиды, сворачиваемые и обходимые типы и т.п. категорные и алгебраические типы и классы как «паттерны» и средства декомпозиции.

                http://rchan.ws/pr/src/1361391985569.png
                Ответить
                • "Делаешь пандорический захват, лифтишь в монаду, потом строишь рекурсивную схему (здесь подойдёт зигохистоморфный препроморфизм ) как монадический трансформер из категории эндофункторов, и метациклически вычисляешь результат. Любой второкурсник справится. А если делать на анафорических лямбдах — так задачка вообще на пять минут."
                  Ответить
          • >А читать про них что-то влом.
            Стареешь, бор. Какой уж десяток разменял?
            Ответить
    • Попробую реабилитироваться: функция solve является композицией nub, filter, блока 7-11, uncurry ($), блока 13-22. Т.к. композиции работают справа налево, начнем раскурку с блока 13-22.

      Блок 13-22 прогоняет аргумент через композицию last, 14-19, uncurry takeWhile и 21, и возвращает результат в виде тупла, наряду с исходным аргументом.

      uncurry (zipWith (,)) . (inits &&& tails) - функция, возвращающая все варианты разбиения списка на два, tail отбросит случай с пустым первым списком, а map преобразует каждый тупл: \(x, y) -> (last x, init x ++ y). В результате получаем функцию, которая возвращает все варианты выборки одного элемента - для [1,2,3] она вернет [(1, [2, 3]), (2, [1, 3]), (3, [1, 2])].

      (uncurry map) . ((:) *** solve') это \(x, y) -> map (x:) $ solve' y. Объединив этот блок с предыдущим с помощью >=> получим функцию, которая вынимает каждый элемент списка, выполняет solve' над оставшимися, и к каждому результату приклеивает в начало вынутый элемент.

      const . null это \x -> \_ -> null x, а const [const [[]]] это \_ -> [\_ -> [[]]] поэтому строка 21 переписывается как \x -> (\_ -> null x, [\_ -> [[]]]). Композиция этой фигни с uncurry takeWhile даст нам \x -> takeWhile (\_ -> null x) [\_ -> [[]]]. Если x пуст, мы получим список из одной функции: [\_ -> [[]]], иначе - пустой список.

      В итоге строки 12-23 возвращают [[]] для пустого списка, а для непустого вынимает каждый элемент списка, выполняет solve' над оставшимися, и к каждому результату приклеивает в начало вынутый элемент. Перепишем эти строки как
      solve2 :: [String] -> [[String]]
      solve2 [] = [[]]
      solve2 xs = concatMap (\(as, bs) -> map (last as:) $ solve' (init as ++ bs)) $ tail $ zip (inits xs) (tails xs)
      to be continued...
      Ответить
    • ((.head).(==).last) можно раскрутить как \x y -> last x == head y. Значит строки 8-11 проверяют правильно ли "сцеплены" строки (первый символ следующей равен последнему предыдущей).

      В результате получаем вот такой код:
      solve2 :: [String] -> [[String]]
      solve2 [] = [[]]
      solve2 xs = concatMap (\(as, bs) -> map (last as:) $ solve' (init as ++ bs)) $ tail $ zip (inits xs) (tails xs)
      
      check (a : b : r) = last a == head b && check (b : r)
      check _ = True
      
      solve' xs = nub $ filter check $ solve2 xs
      А задача была примерно такой - "найти все перестановки исходных строк, при которых они будут правильно сцеплены (последний символ предыдущей равен первому символу следующей)".
      Ответить
      • import Data.List
        
        solve = nub . filter check . permutations xs where
            check (a : b : r) = last a == head b && check (b : r)
            check _ = True
        
        main = print $ solve ["123", "324", "421"]
        Ответить
        • Круто ты. Напиши себе в резюмэ: Умение читать говнокод на Хаскеле
          Ответить
          • Ну или умение пользоваться @pl и @unpl Лямбда-бота. А Борманду — респект.
            Ответить
            • > @pl и @unpl Лямбда-бота
              Что это и где это?
              Ответить
              • Ирк бот на хаске. С ним можно пообщаться на chat.freenode.net #haskell если верить описанию. Для данной ситуации он полезен тем, что умеет преобразовывать код в point-free и обратно.

                P.S. Но юзать лямбдабота не спортивно ;)
                Ответить
                • А почему называется point free, если . точки . обычно . наоборот . появляются . в нем?
                  Ответить
                  • Это dot'ы а не point'ы.
                    Ответить
                    • Твой ник у меня позеленел. И то и то точка.
                      Ответить
                      • тора-гой товаг'ищ, не путаем синтаксис с содержанием: таки (.) композиция</mode-поддавшегося-троллингу>
                        Ответить
                        • Леонид Ильич, поясни и мне почему поинтфри называют именно безточечной? Это какие такие точки пропали?
                          Ответить
              • Это бот для хаскельных чатов (например, канал #haskell на chat.freenode.net). Помимо прочих талантов (в основном используется как REPL и hoogle), умеет переводить выражения в пойнт-фри и обратно.
                Ответить

    Добавить комментарий