2015-12-20 2 views
3

Я пытаюсь сделать функцию, которая суммирует значения не двоичного целого дерева.Суммирование целочисленного дерева (Haskell)

-- datastructures.hs  
data Tree a = Empty | Node a [Tree a] deriving (Eq, Show) 

myNums :: (Num a) => Tree a 
myNums = Node 1 [ 
      Node 2 [ 
      Node 4 [Empty], Node 5 [Empty] 
      ], 
      Node 3 [ 
      Node 6 [Empty], Node 7 [Empty], Node 8 [Empty] 
      ] 
     ] 

addNums :: (Num a) => Tree a -> a 
addNums Empty = 0 
addNums (Node n [Empty]) = n 
addNums (Node n (x:xs)) = n + (addNums x) + (addNums xs) 

В идеале я хотел бы addNums myNums быть 36, но это приводит к ошибке:

datastructures.hs:20:54: 
    Couldn't match expected type ‘Tree a’ with actual type ‘[Tree a]’ 
    Relevant bindings include 
     xs :: [Tree a] (bound at datastructures.hs:20:20) 
     x :: Tree a (bound at datastructures.hs:20:18) 
     n :: a (bound at datastructures.hs:20:15) 
     addNums :: Tree a -> a (bound at datastructures.hs:18:1) 
    In the first argument of ‘addNums’, namely ‘xs’ 
    In the second argument of ‘(+)’, namely ‘(addNums xs)’ 

Как противостоять этому, и каковы лучшие практики?

РЕДАКТ. Лучшие практики, похоже, полностью исключают Empty! Я забыл, что [] является действительным экземпляром типа [Tree a]. Так что лучший способ осуществить это:

data Tree a = Node a [Tree a] deriving (Eq, Show) 

addNums :: (Num a) => Tree a -> a 
addNums (Node n []) = n 
addNums (Node n (x:xs)) = n + (addNums x) + addNums (Node 0 xs) 
+0

'(addNum х) + (addNum хз)'. Не работает. 'x' и' xs' здесь имеют разные типы. –

+0

Это не работает: 'addNums (Node n (x: xs)) = n + (addNums x) + foldl1 (\ acc t -> acc + addNums t) xs' –

+1

' addNums (Node n xs) = foldl (\ a -> (+) a. addNums) n xs' – user2407038

ответ

2

Проблема заключается в двух последних строках своего addNums определения. Вы должны проверить пустой базовый регистр, а не когда список содержит один элемент с Empty внутри него. Нечто подобное должно работать:

addNums :: (Num a) => Tree a -> a 
addNums Empty = 0 
addNums (Node n []) = n 
addNums (Node n (x:xs)) = n + (addNums x) + addNums (Node 0 xs) 

Обратите внимание, что для пустого списка вы только возвращающегося n. И когда список содержит более одного элемента, вы рекурсивно суммируете его до тех пор, пока он не достигнет случая bae (список становится пустым).

Demo в ghci:

λ> addNums myNums 
36 
+0

Мне потребовалась минута, чтобы понять, зачем вам нужен шаблон '[]' (поскольку любое '[Tree a]' должно содержать как минимум 'Empty', но теперь я вижу, что вы оцениваете его против своего собственного узла Node 0 '.Это кажется неудобным: существует ли наилучшая практика для такого дерева? –

+2

@MarkKaravan Даже тогда вам нужно проверить' '], или иначе совпадение шаблона будет не исчерпывающим. Вы можете абстрагировать всю вещь, используя' foldl', так как пользователь2407038 продемонстрировал. – Sibi

3

Возможное решение:

addNums :: (Num a) => Tree a -> a 
addNums Empty = 0 
addNums (Node n xs) = n + sum (map addNums xs) 

В рекурсивном случае, у нас есть список деревьев xs. Мы можем использовать addNums на каждом из этих деревьев, получив список чисел. Затем мы просто суммируем их и добавляем корень n.

5

Просто получить Foldable и использовать существующий sum:

{-# LANGUAGE DeriveFoldable #-} 

data Tree a = Empty | Node a [Tree a] deriving (Eq, Show, Foldable) 

myNums :: (Num a) => Tree a 
myNums = ... 

main = print $ sum myNums 
+0

Удивительно. Есть ли какая-либо стоимость для этой стратегии? –

+1

@Mark Karavan, [yes] (http://osa1.net/posts/2015-11-13-data-repr-1. html), а также в других ответах, он протекает. Вы можете использовать 'fastSum = foldl '(+) 0' (' foldl'' также поставляется с 'Foldable'), но я не был бы удивлен, если бы он утечки тоже.Вы можете задать еще один вопрос об эффективном суммировании чисел в дереве. – user3237465

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