2010-12-13 2 views
15

Я нетерпелив, глядя вперед к пониманию катаморфизма related to this SO question :)катаморфизм и дерево-обход в Haskell

я только практиковал начало Real World Haskell учебника. Итак, может быть, я сейчас попробую слишком много, если это так, просто скажите мне те понятия, которые я должен изучить.

Ниже приводится цитата из wikipedia code sample for catamorphism.

Хотелось бы узнать ваше мнение о foldTree ниже, способ пересечения дерева, по сравнению с этим другим вопросом и ответом, также касающимся пересечения дерева n-ary tree traversal. (независимо от того, чтобы быть бинарным или нет, я думаю, что катаморфизм ниже может быть написан так, чтобы управлять n-арным деревом)

Я поставил комментарий, что я понимаю, и будьте рады, если вы можете исправить меня и прояснить некоторые вещи ,

{-this is a binary tree definition-} 
data Tree a = Leaf a 
      | Branch (Tree a) (Tree a) 

{-I dont understand the structure between{} 
however it defines two morphisms, leaf and branch 
leaf take an a and returns an r, branch takes two r and returns an r-} 
data TreeAlgebra a r = TreeAlgebra { leaf :: a  -> r 
            , branch :: r -> r -> r } 

{- foldTree is a morphism that takes: a TreeAlgebra for Tree a with result r, a Tree a 
and returns an r -} 
foldTree :: TreeAlgebra a r -> Tree a -> r 
foldTree [email protected](TreeAlgebra {leaf = f}) (Leaf x ) = f x 
foldTree [email protected](TreeAlgebra {branch = g}) (Branch l r) = g (foldTree a l) (foldTree a r) 

в этот момент у меня возникло много трудностей, я, кажется, догадывается, что морфизм лист будет применен к любому Leaf Но для того, чтобы использовать этот код для реального, foldTree должен быть подан определенным TreeAlgebra , a TreeAlgebra, которая имеет определенный лист морфизма, чтобы что-то сделать?
, но в этом случае в коде foldTree я бы ожидал {f = leaf}, а не наоборот

Любые разъяснения от вас были бы очень желанными.

+0

Несвязанное примечание: метка «catamporphisms» имеет орфографическую ошибку; он имеет дополнительный «p». По-видимому, я недостаточно крут, чтобы редактировать это, но это создало бы новый тег. (Иисус плакал.) –

+0

@ Деррик Тюрк: с этим тегом всего три вопроса. Было бы не слишком сложно их отталкивать. – fuz

+0

@FUZxxl: Кажется, вам нужна репутация 1500 для создания новых тегов, и в то время «катаморфизм» еще не существовал. – ephemient

ответ

26

Не совсем уверен, что вы просите. Но да, вы кормите TreeAlgebra до foldTree, соответствующих вычислениям, которые вы хотите выполнить на дереве. Например, чтобы просуммировать все элементы в дереве Int с вы могли бы использовать эту алгебру:

sumAlgebra :: TreeAlgebra Int Int 
sumAlgebra = TreeAlgebra { leaf = id 
         , branch = (+) } 

значит, чтобы получить сумму листа, применять id (ничего не делать) до значения в листе , Чтобы получить сумму филиала, добавьте суммы каждого из детей.

Тот факт, что мы можем сказать (+) для ответвления вместо, скажем, \x y -> sumTree x + sumTree y, является основным свойством катаморфизма. В нем говорится, что для вычисления некоторой функции f для некоторой рекурсивной структуры данных достаточно иметь значения для ее непосредственных детей.

Haskell - довольно уникальный язык, позволяющий абстрактно абстрагировать идею катаморфизма. Давайте создадим тип данных для одного узла в вашем дереве, параметризованный над его дочерними элементами:

data TreeNode a child 
    = Leaf a 
    | Branch child child 

Посмотрите, что мы там делали? Мы просто заменили рекурсивных детей типом нашего выбора. Это так, что мы можем поместить суммы поддеревьев там, когда мы складываемся.

Теперь для действительно волшебной штуки. Я собираюсь написать это в псевдохаскелле - писать его в реальном Haskell возможно, но мы должны добавить некоторые аннотации, чтобы помочь typechecker, который может быть довольно запутанным. Мы берем «фиксированную точку» параметризованного типа данных, т. Е. Создаем тип данных T, такой как T = TreeNode a T. Они называют этого оператора Mu.

type Mu f = f (Mu f) 

Обращайте внимание здесь. Аргументом к Mu не является тип, например Int или Foo -> Bar. Это тип конструктор как Maybe или TreeNode Int - аргумент Mu сам принимает аргумент. (Возможность абстрагирования над конструкторами типов является одной из вещей, которая делает систему типа Haskell действительно выделяющейся в ее выразительной силе).

Таким образом, тип Mu f определяется как взятие f и заполнение его параметром типа Mu f. Я собираюсь определить синоним, чтобы уменьшить часть шума:

type IntNode = TreeNode Int 

Расширение Mu IntNode, мы получаем:

Mu IntNode = IntNode (Mu IntNode) 
      = Leaf Int | Branch (Mu IntNode) (Mu IntNode) 

Вы видите, как Mu IntNode эквивалентно вашей Tree Int? Мы просто разорвали рекурсивную структуру, а затем использовали Mu, чтобы снова собрать ее обратно. Это дает нам преимущество, что мы можем говорить обо всех типах Mu сразу. Это дает нам то, что нам нужно определить для катаморфизма.

Давайте определим:

type IntTree = Mu IntNode 

Я сказал, что существенное свойство катаморфизма является то, что для вычисления некоторой функции f, достаточно иметь значение f для своих непосредственных детей. Давайте назовем тип вещи, которую мы пытаемся вычислить r, и структура данных node (IntNode была бы возможной инстанцировкой этого). Поэтому, чтобы вычислить r на конкретном узле, нам нужен узел со своими детьми, замененными их r. Этот расчет имеет тип node r -> r. Так катаморфизм говорит, что если у нас есть один из этих расчетов, то мы можем вычислить r для всей рекурсивной структуры (помните рекурсии обозначаются здесь явно с Mu):

cata :: (node r -> r) -> Mu node -> r 

Созданием этого бетона для нашего примера, это выглядит следующим образом:

cata :: (IntNode r -> r) -> IntTree -> r 

Подтвердив, если мы можем взять узел с r с для своих детей и вычислить r, то мы можем вычислить r для всего дерева ,

Для того, чтобы действительно вычислить это, нам нужно node быть Functor. То есть нам нужно иметь возможность сопоставлять произвольную функцию по дочерним элементам узла.

fmap :: (a -> b) -> node a -> node b 

Это можно сделать прямо на IntNode.

fmap f (Leaf x) = Leaf x     -- has no children, so stays the same 
fmap f (Branch l r) = Branch (f l) (f r) -- apply function to each child 

Теперь наконец, мы можем дать определение для cata (Functor node ограничения просто говорит, что node имеет подходящую fmap):

cata :: (Functor node) => (node r -> r) -> Mu node -> r 
cata f t = f (fmap (cata f) t) 

Я использовал имя параметра t для мнемоники значение «дерева». Это абстрактное, плотное определение, но это действительно очень просто. В нем говорится: рекурсивно выполнить cata f - расчет, который мы делаем над деревом - на каждом из t детей (которые сами являются Mu node), чтобы получить node r, а затем передать этот результат f для вычисления результата для t ,

Привязывая это к началу, алгебра, которую вы определяете, по существу является способом определения функции node r -> r. Действительно, учитывая TreeAlgebra, мы можем легко получить фолд функцию:

foldFunction :: TreeAlgebra a r -> (TreeNode a r -> r) 
foldFunction alg (Leaf a) = leaf alg a 
foldFunction alg (Branch l r) = branch alg l r 

Таким образом, дерево катаморфизм может быть определена в терминах нашего общего одного следующим образом:

type Tree a = Mu (TreeNode a) 

treeCata :: TreeAlgebra a r -> (Tree a -> r) 
treeCata alg = cata (foldFunction alg) 

Я вне времени , Я знаю, что очень быстро стал очень абстрактным, но я надеюсь, что он по крайней мере дал вам новую точку зрения, чтобы помочь вам в обучении. Удачи!

+0

Много много многого для этого тщательного ответа. –

4

Думаю, вы задавали вопрос о {}. Существует более ранний вопрос с хорошим обсуждением {}. Они называются Haskell's record syntax. Другой вопрос - зачем строить алгебру. Это типичная парадигма функции, в которой вы обобщаете данные как функции.

Самым известным примером является Church's construction of the Naturals, где f = + 1 и z = 0, 0 = z, 1 = f z, 2 = f (f z), 3 = f (f (f z)), и т.д ...

То, что вы видите, по существу, та же идея применяется к дерево. Работайте над примером церкви, и дерево щелкнет.

Смежные вопросы