Рекурсия
Я это как-то писал, но напишу ещё раз, бо тема поднялась.
Недостатки явной рекурсии по сравнению с комбинаторами (ага, zip3):
Юный хаскеллист, избегай явной рекурсии!
Ну и ссылочка, куда без неё!
Недостатки явной рекурсии по сравнению с комбинаторами (ага, zip3):
- Рекурсия непонятна (согласен, это субъективное).
- Обычно используется с декомпозицией, нарушая инкапусляцию.
- Всегда используется для работы с элементами, вместо работы с коллекцией (wholemeal programming).
- Цепочка вызовов проще для оптимизации.
- Сложнее нежно мною любимый equational reasoning.
Юный хаскеллист, избегай явной рекурсии!
Ну и ссылочка, куда без неё!
no subject
no subject
2. Этот пост возник из-за этой дискуссии (http://levgem.livejournal.com/420910.html?thread=5124654#t5124654). Т.е. "как заменить" уже есть.
Не стоит заменять. Если нужно, скажем, делать разбор двух структур по условию, то я пишу рекурсивный код. Пример: merge двух сортированных списков.
no subject
no subject
В качестве возможного примера могу предложить Omega monad: http://hackage.haskell.org/package/control-monad-omega
Комбинатор рекурсивной обработки потенциально бесконечных списков с гарантированным перечислением всех элементов.
no subject
Где, грубо говоря, file -- это исходник, а module -- директория. Нужно написать функцию, которая применит функцию компиляции к каждому исходному файлу, причём в правильном порядке, с учётом что от чего зависит.
Для данного примера порядок может быть таким: f1, f2, f4, f5, f3, f6, f0, f7.
В идеале ещё бы обнаружить циклические зависимости.
Как это сделать двойной рекурсией -- очевидно, а вот комбинаторного решения я придумать не могу.
no subject
http://www.haskell.org/haskellwiki/Scrap_your_boilerplate
(есть ещё более навороченные и/или удобные варианты, более поздние)
Например, одной строкой можно получить все файлы. Другой - все зависимости. Отображение (map compile) на файлы даст компиляцию и тп.
Наверное, это ближе всего к нужному тебе.
no subject
no subject
no subject
Сортируем пары вида (файл, зависимость) вот таким сравнением:
compareTopo (fa,depsa) (fb,depsb)
| fa `elem` depsb && fb `elem` depsa = error "cycle!"
| fa `elem` depsb = LT
| otherwise = EQ
sortDeps = sortBy compareTopo filesDeps
Первыми должны оказаться файлы без зависимостей.
Не однострочник, но близко.
no subject
Единственное, не могу сообразить, как scrap your boilerplate позволит мне одной строкой собрать из дерева все зависимости всех файлов, но верю на слово, что такое возможно.
no subject
Выхлоп: Похоже на правду.
no subject
А на циклы проверяли? Что-то меня смущает проверка на циклы. По идее зависимости должны раскрываться, но они тут раскрываться будут бесконечно в случае цикла. Банально f0 = File "f0" [f0].
(no subject)
(no subject)
no subject
В принципе, всё очевидно: двойная рекурсия спрятана в двух вложенных через map listify, которые, в свою очередь (если я ничего не путаю), просто выполняют flatten дерева.
Тогда, если можно, встречный теоретический вопрос: а как правильно в хаскеле оценить производительность алгоритма, учитывая ленивость языка и автоматическую мемоизацию? Например, в императивном языке в таком решении достаточно паскудная сложность, и двойная рекурсия будет несравнимо оптимальней.
(no subject)
(no subject)
no subject
no subject
У вас появляется шанс поправить и понять, что не так. ;)
Поправите?
(no subject)
(no subject)
(no subject)
no subject
Он на ней деньги собирался зарабатывать. ;)
no subject
Идея такая:
1. Строим список пар (имя объекта, непосредственные зависимости). Для файла это зависимости, для модуля - имена компонентов.
2. Строим дерево зависимостей, т.е. разворачиваем непосредственные зависимости.
3. Сортируем очевидным образом (зависящий идёт позже, если независимы - по имени)
4. Вуаля
Код без учёта циклических зависимостей: http://hpaste.org/78574
Для учёта идея проста, мы храним "родителей" и смотрим, чтобы текущий от них не зависел: http://hpaste.org/78575
Update
Я был не прав в пункте 3, сортировать не нужно. Вот конечный результат: http://hpaste.org/78585
no subject
Индуктивные типы — это деревья. Графы делают из них и напрямую, без соответствующего вычислятельного контекста, индуктивными типами они не являются.
Тем не менее, для графов можно сделать соответствующие комбинаторы.
Первыми ну просто напрашиваются всякие преобразования в процессе обхода графа в ширину-глубину.
Ещё строят построение (ленивого) дерева обхода и что-то-там с ним дальше делают.
no subject
Последнее решение я, правда, уже не особо понимаю, но это чисто из-за слабого знания содержимого стандартной библиотеки хаскеля.
no subject
no subject
http://hpaste.org/78589 (http://hpaste.org/78589)
no subject
no subject
http://hpaste.org/78604
Data.Functor.Fixedpoint находится в unification-fd, импорт можно заменить на ровно две строчки:
newtype Fix f = Fix { unFix :: f (Fix f) }
cata phi = phi . fmap self . unFix
no subject
no subject
но для того, чтобы избежать явной рекурсии это не обязательно. например, в данном случае берем рекурсивный алгоритм из википедии (http://en.wikipedia.org/wiki/Topological_sort, второй) и пишем его в лоб: http://hpaste.org/78601
основная функция получилась так:
Код сурово императивный, что видно по foldr, но хотя бы нет явной структурной рекурсии.
Как известно, вместо рекурсии можно использовать цикл с очередью (http://hpaste.org/78602):
Код по-прежнему императивный, но явной рекурсии больше нет. Она спрятана в until и foldr.
Если все немного обобщить (разрешить зависимости и на уровне модулей, чтобы структура была более симметричная) и причесать, то можно избавиться от рекурсии и во flatten, перенеся ее в общий комбинатор foldTree: http://hpaste.org/78603