[英]Haskell n-ary tree traversal
我對Haskell很新,我正在努力研究如何遍歷一棵n-ary樹。 作為輸出,我希望獲得Leaf值列表(因為分支沒有值),因此對於testtree,這將是:4,5
到目前為止我的定義是:
data Tree a = Leaf a | Branch [Tree a] deriving (Show)
travTree :: Tree a -> [a]
travTree (Leaf x) = [x]
travTree (Branch (x:xs)) = travTree x : travTree xs
testtree = Branch [(Leaf "4"), (Leaf "5")]
但它給出了錯誤:
Couldn't match expected type `Tree a'
against inferred type `[Tree a]'
In the first argument of `travTree', namely `xs'
In the second argument of `(:)', namely `travTree xs'
In the expression: travTree x : travTree xs
我假設這是因為xs是一個樹列表,它期待一棵奇異的樹。 有沒有辦法做到這一點? 我一直在嘗試地圖功能,順序如下:
travTree (Branch (x:xs)) = travTree x : map travTree xs
但它抱怨說:
Occurs check: cannot construct the infinite type: a = [a]
When generalising the type(s) for `travTree'
我也嘗試將函數簽名更改為:
travTree :: Tree a -> [b]
這給出了錯誤:
Couldn't match expected type `a' against inferred type `[b]'
`a' is a rigid type variable bound by
the type signature for `travTree' at Main.hs:149:36
In the first argument of `(:)', namely `travTree x'
In the expression: travTree x : map travTree xs
In the definition of `travTree':
travTree (Branch (x : xs)) = travTree x : map travTree xs
任何幫助將不勝感激,所以提前感謝..!
你在右邊線與map
,但遍歷每個子樹后要concat
所產生的名單一起。 使用map
時,使用(x:xs)
模式切斷列表的第一個元素也沒有意義。 我寫這個:
travTree (Branch xs) = concatMap travTree xs
(但要注意;我沒有測試過!但是我經常發現我的“無限類型a = [a]”問題是由需要concatMap
的map
引起的。)
遍歷樹意味着遍歷所有子樹並將生成的列表展平為一個。
這轉化為
travTree (Branch branches) = concat $ map travTree branches
請注意,對於此定義的右側,還有更簡潔的符號,例如branches >>= travTree
或concatMap travTree branches
,但我認為上面的concatMap travTree branches
是最清晰的。
編輯:為了完整性重新引入列表理解版本:
travTree (Branch branches) = [ elem | br <- branches, elem <- travTree br ]
當我剛接觸Haskell時,我遇到了同樣的問題。 我終於找到了如何通過放慢速度並查看類型來解決問題。 (當我寫了很多Scheme時,我反而放慢速度並查看非常簡單的輸入/輸出對。我有時會在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]
。
其他答案是正確的說,這里的解構是沒有意義的,但我希望看到拼出的類型有助於你理解如何模仿你頭腦中的類型推斷。 這樣你就可以解決其他類似問題的問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.