Когда я был новичком в Haskell, я часто сталкивался с той же проблемой. В конце концов я понял, как решить проблему, замедляя и рассматривая типы. (Назад, когда я написал много Схем, я вместо этого замедлил и смотрю на очень простые пары ввода / вывода. Я делаю это иногда в Haskell, но не до тех пор, пока не посмотрю на типы.)
travTree :: Tree a -> [a]
travTree (Leaf x) = [x]
travTree (Branch (x:xs)) = travTree x : travTree xs
Ваш тип выглядит правильно: Tree a -> [a]
звучит как "все листья" для меня.
travTree (Leaf x) = [x]
Этот случай правильно конвертирует Tree a
в [a]
.
travTree (Branch (x:xs)) = travTree x : travTree xs
ОК, ввод определенно Tree a
. Если выходные данные должны быть [a]
, а первый оператор - (:) :: a -> [a] -> [a]
, тогда нам нужны travTree x :: a
и travTree xs :: [a]
. Это работает?
Ну, это не работает по двум причинам: на самом деле, travTree x :: [a]
, и вы не можете добавить список в другой список (для этого вам нужно (++) :: [a] -> [a] -> [a]
). И вы не можете передать [Tree a]
на travTree :: Tree a -> [a]
- вы даете ему список деревьев, когда он ожидает одно дерево.
Вы можете решить вторую проблему, используя map
: map travTree xs
. Это имеет тип [Tree a] -> [[a]]
. К счастью, теперь это соответствует travTree x :
, так что
(travTree x : map travTree xs) :: [[a]]
Теперь у вас есть проблема с [[a]]
вместо [a]
. concat
решает эту проблему путем выравнивания один раз, поэтому
travTree (Branch (x:xs)) = concat (travTree x : map travTree xs) :: [a]
, что соответствует ожидаемому Tree a -> [a]
.
Другие ответы верны, когда говорят, что деструктурирование здесь бессмысленно, но я надеюсь, что видение прописанных типов поможет вам понять, как имитировать вывод типа в вашей голове. Таким образом, вы можете решить, что идет не так для других, подобных проблем.