[英]How to write a function of type `[(a,b)] -> ([a] -> [a]) -> [(a,b)]`
[英]How to write a function of type a-> b -> b -> b for folding a tree
一些背景:我在Haskell中有以下類型的foldT函數(如foldr但對於樹)。
foldT :: (a -> b -> b -> b) -> b -> Tree a -> b
此foldT僅將類型(a - > b - > b - > b)作為輸入函數。
我試圖找到一種方法將我的樹轉換為一個列表,並無法找到一種方法使我的追加函數采取形式(a - > b - > b - > b)。
以下是無效的,因為它不是正確的類型:
append x y z = append x:y:z
任何幫助,將不勝感激。
謝謝!
由於你沒有發布它,我會假設你的樹是......
data Tree a = Leaf | Node a (Tree a) (Tree a)
...而且, foldT
的a -> b -> b -> b
參數以與聲明它們相同的順序獲取Node
構造函數的字段。
我試圖找到一種方法將我的樹轉換為列表
讓我們按照以下類型開始解決這個問題:
foldT :: (a -> b -> b -> b) -> b -> Tree a -> b
您希望將其展平為列表,因此函數的結果類型必須為[a]
:
treeToList :: Tree a -> [a]
這讓我們知道如何繼續:
treeToList t = foldT f z t
附:
f :: a -> [a] -> [a] -> [a]
z :: [a]
t :: Tree a
現在,繼續論證。 z
將代替無價值的Leaf
s插入,因此它必須是[]
。 至於f
,它必須將從左右分支創建的子列表與Node
的值直接組合在一起。 假設有序遍歷,我們有:
treeToList t = foldT (\x l r -> l ++ x : r) [] t
或者,沒有提到t
:
treeToList = foldT (\x l r -> l ++ x : r) []
就是這樣。 需要注意的是,重復使用左嵌套(++)
(在這種情況下會發生,因為foldT
遞歸地向下foldT
分支)可能會非常低效。 在您關心性能的情況下,值得考慮實現連接函數的替代方法,例如差異列表 。
PS:關於術語的說明。 說一個函數“像折疊器但是對於樹”是不明確的,因為有兩種眾所周知的類似於foldr
的函數。 首先,你有Foldable
類的方法(參見Benjamin Hodgson的答案 ),無論你做什么,它都會將樹折成一個列表。 然后是更強大的catamorphisms ,例如你正在使用的foldT
,它們能夠利用樹結構。
如果要將樹轉換為列表,那么函數相對容易,所以基本上如果你有樹結構,例如:
data Tree a = Leaf | Node (Tree a) a (Tree a) deriving (Eq, Ord, Show)
然后你必須從樹中提取值並將第一個值添加到空列表中,然后在list(++)運算符的幫助下遞歸地將相同的方法應用於樹的其他分支以附加所有結果到一個列表,即:
toList :: Tree a -> [a]
toList Leaf = []
toList (Node left value right) = [value] ++ toList left ++ toList right
然后折疊它,首先:
foldT :: (a -> b -> b -> b) -> b -> Tree a -> b
函數簽名缺少一個參數這里讓我們看一下簽名: a(第一個參數) - > b(第二個) - > b(第三個) - > b(返回類型)函數接受3個參數 /參數但你提供的簽名 只有1 b類型 (我猜你的累加器),所以基本上這將是你正在尋找的函數簽名:
foldT :: (a -> b -> b) -> b -> Tree a -> b
現在我們可以使用這個簽名,然后讓我們進入函數:
foldT :: (a -> b -> b) -> b -> Tree a -> b
foldT f acc Leaf = acc
foldT f acc (Node left value right) = foldT f (foldT f (f value acc) left) right
雖然我不認為我應該給你答案,你應該用遞歸數據結構練習更多,這樣你就可以更好地理解如何遍歷它們。
PS:如果你打算投票給我,那么至少要解釋一下原因!
你每次開始的第一件事就是開始匹配模式:)那時,它幾乎是機械的!
假設你有:
data Tree a = Leaf | Node (Tree a) a (Tree a)
讓我們開始匹配模式吧! :)
foldT :: (a -> b -> b -> b) -> b -> Tree a -> b
foldT f z ...
什么是第一個Tree
構造函數? 這是Leaf
!
foldT :: (a -> b -> b -> b) -> b -> Tree a -> b
foldT f z Leaf = ...
我們可以放在那里? 我們需要類型為b
東西......我們只有一種方法可以獲得它。 通過使用z
:)
foldT :: (a -> b -> b -> b) -> b -> Tree a -> b
foldT f z Leaf = z
因此,從機械上講,我們可以繼續下一個可能的模式:
foldT :: (a -> b -> b -> b) -> b -> Tree a -> b
foldT f z Leaf = z
foldT f z (Node t1 x t2) =
好吧,我們可以把它做成z
,但那有點無聊。 我們可能想要使用t1
, x
和t2
。 我們可以使用f
,它需要類型a
東西......我們有x :: a
:)
foldT :: (a -> b -> b -> b) -> b -> Tree a -> b
foldT f z Leaf = z
foldT f z (Node t1 x t2) = f x ??? ???
f
還有兩個b
類型的參數,那么你認為我們可以把它放在那里? 我們可以把z
放兩次,但那有點無聊。 我們怎么能從t1
和t2
得到b
?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.