реализация катаморфизма для недвоичных деревьев по сравнению с составным шаблоном проектирования - PullRequest
1 голос
/ 20 января 2011

На данный момент мечта все еще продолжается, в каждой концепции Haskell я узнаю, что я более заманчивый. И все же я не полностью выполнил работу над ответом этого драгоценного @ luqui на мой предыдущий вопрос о катаморфизме , и я собираюсь вернуться к нему, пока все не будет в порядке. Это был пример кода в Википедии, посвященный катаморфизму на деревьях BINARY .

Тем не менее, я попытался реализовать катаморфизм для NIN BINARY деревьев, но у меня возникли некоторые проблемы:

data Composition a = Leaf a
                   | Composite [Composition a]

data CompositionAlgebra a r = CompositionAlgebra { leaf      :: a →  r
                                                 , composite :: [r] →  r }

foldComposition :: CompositionAlgebra a r →  Composition a →  r
foldComposition a@(CompositionAlgebra {leaf   = f}) (Leaf   x  ) = f x
foldComposition a@(CompositionAlgebra {composite = g}) (Composite [y]) =  map g [y] 

- эта последняя строка не соответствует ghc на "map g [y]"

maxOfPair :: a →  a →  a
maxOfPair x y = if( x > y) -- this doesnt please ghc either, Ordering trouble
                then (x) 
                else (y)

maxInList :: [a] →  a
maxInList (x:xs) = maxOfPair x (maxInList xs)

treeDepth :: CompositionAlgebra a Integer
treeDepth = CompositionAlgebra { leaf = const 1, composite = λx →  1 + maxInList x }

sumTree :: (Num a) ⇒ CompositionAlgebra a a
sumTree = CompositionAlgebra { leaf = id, composite = (+) } 

- и эта последняя сумма не подходит для ghc

Я вижу> и +, так же, как операторы C ++> и +. Так что я не понимаю, что ghc злится на меня, если я не даю этому объекту реализацию opertor> / + или нет.

Во-вторых, я должен признать, что совершенно не уверен в смысле => (отличается от -> ???) и @, который, похоже, напоминает руководство по сопоставлению с образцом.

Как бы вы исправили этот код?

И последний вопрос, Я также пытаюсь сделать это, потому что Composite Pattern оказался самым важным для меня в C ++. И, очевидно, я вижу, что это почти можно описать только одной / двумя строками в Haskell (это действительно удивительно для меня).

Но как бы вы сказали людям, что Leaf и Composite конструктор Composition могут иметь один и тот же интерфейс? (Я знаю, что это нехорошее слово, поскольку данные не являются изменяемыми, но я надеюсь, что вы можете угадать - понять мою проблему / цель)

это общая ошибка компиляции;

src\Main.hs:27:79:
    Couldn't match expected type `[r]'
           against inferred type `Composition a'
    In the expression: y
    In the second argument of `map', namely `[y]'
    In the expression: map g [y]

src\Main.hs:30:20:
    Could not deduce (Ord a) from the context ()
      arising from a use of `>' at src\Main.hs:30:20-24
    Possible fix:
      add (Ord a) to the context of the type signature for `maxOfPair'
    In the expression: (x > y)
    In the expression: if (x > y) then (x) else (y)
    In the definition of `maxOfPair':
        maxOfPair x y = if (x > y) then (x) else (y)

src\Main.hs:41:0:
    Occurs check: cannot construct the infinite type: a = [a] -> [a]
    When generalising the type(s) for `sumTree'

EDIT Так что это окончательная версия для недвоичного катаморфизма

data Composant a = Leaf a
                 | Composite [Composant a]

data CompositionAlgebra a r = CompositionAlgebra { leaf      :: a →  r
                                             , composite :: [r] →  r }

foldComposition :: CompositionAlgebra a r →  Composant a →  r
foldComposition a@(CompositionAlgebra {leaf = f}) (Leaf x) = f x
foldComposition a@(CompositionAlgebra {composite = g}) (Composite ys) =  g(map(foldComposition a) ys)

maxOfPair :: Ord a ⇒ a →  a →  a
maxOfPair x y = if( x > y) 
                then (x) 
                else (y)

maxInList :: Ord a => [a] →  a
maxInList (x:xs) = maxOfPair x (maxInList xs)

treeDepth :: CompositionAlgebra a Integer
treeDepth = CompositionAlgebra { leaf = const 1, composite = λx →  1 + maxInList x }

addList :: Num a ⇒ [a] → a
addList (x:xs) = x + addList xs 

sumTree :: (Num a) ⇒ CompositionAlgebra a a
sumTree = CompositionAlgebra { leaf = id, composite = addList } 

И в соответствии с действительным ответом ниже: то, что я просил для haskell-эквивалента контрактов C ++ Interfaces, похоже, является ограничениями классов типов.

Таким образом, шаблон проектирования Composite будет достигнут путем применения ограничений класса типов при создании Composition a. Возможно, новые специализированные данные должны быть определены. Но я должен выучить классы типов, прежде чем делать это: -)

Ответы [ 2 ]

5 голосов
/ 20 января 2011

Здесь есть несколько разных ошибок, поэтому я не уверен, что лучший способ справиться с этим на SO, но какого черта.

В будущем постарайтесь включить больше ошибок, которые предоставляет GHC.

В:

foldComposition :: CompositionAlgebra a r →  Composition a →  r
foldComposition a@(CompositionAlgebra {leaf   = f}) (Leaf   x  ) = f x
foldComposition a@(CompositionAlgebra {composite = g}) (Composite [y]) =  map g [y]

Функция foldCompose имеет две ошибки, которые я вижу, только одна из которых будет обнаружена средством проверки типов.

  1. Вы соответствуете шаблону на (Composite [y]), который будет совпадать только для списков одного элемента. Вы, вероятно, хотите (Composite ys), который связывает ys со всем списком.

  2. map g [y] не пройдет проверку типа, потому что вы уже определили g как получение списка r, но вы предоставляете ему список a.

    Чтобы преобразовать a в r, вам необходимо применить к нему CompositionAlgebra: g (map (foldComposition a) ys)

Так что я бы написал это как:

foldComposition :: CompositionAlgebra a r →  Composition a →  r
foldComposition a@(CompositionAlgebra {leaf   = f}) (Leaf   x  ) = f x
foldComposition a@(CompositionAlgebra {composite = g}) (Composite ys) = g (map (foldComposition a) ys)

Для вашей следующей ошибки:

maxOfPair :: a →  a →  a
maxOfPair x y = if( x > y) -- this doesnt please ghc either, Ordering trouble
                then (x) 
                else (y)

В Haskell переменная типа (например, a здесь), все ее одинокие могут быть заполнены любым типом вообще вызывающим, по выбору вызывающего.

Это означает, что в вашей подписи типа вы утверждаете, что функция maxPair будет работать для каждого типа ввода. GHC жалуется (по-своему), что оператор > не работает для каждого типа, и поэтому отказывается компилировать вашу программу.

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

Правильная сигнатура типа:

maxOfPair :: Ord a => a →  a →  a

Который применяет ограничение Ord к типу a.

Кроме того, вы должны использовать стандартную функцию max.

3 голосов
/ 20 января 2011

Во-вторых, я должен признать, что я полностью смутно о смысле => (разные от -> ???) и @, который, кажется, как руководство для сопоставления с образцом.

Содержит функцию elem , которая проверяет, содержит ли список определенное значение. Вы можете определить это как

elem _ [] = False
elem x (y:ys) | x == y = True
              | otherwise = elem x ys

Какая подпись имеет эту функцию? Похоже, elem :: a -> [a] -> Bool. Но компилятор будет жаловаться, потому что вы написали x == y, и не для каждой a определена == функция, только для тех a, которые находятся в Eq типе класса . Таким образом, вам нужно указать что-то вроде «Для всех, которые находятся в уравнении ...». И именно для этого вам нужно =>. Таким образом, правильная подпись для elem является elem :: Eq a => a -> [a] -> Bool.

@ дает вам возможность дать название всей структуре и одновременно сопоставить ее с шаблоном. Например. если у вас есть шаблон a@(x:xs) и вы вызываете эту функцию с помощью [1,2,3,4], тогда a равно [1,2,3,4], x равно 1 и xs равно [2,3,4].

...