簡體   English   中英

在 f# 中折疊/遞歸多路樹

[英]Fold / Recursion over Multiway Tree in f#

我正在嘗試調整 Brian's Fold for Binary Trees ( http://lorgonblog.wordpress.com/2008/04/06/catamorphisms-part-two/ ) 以申請多路樹。

來自 Brian 博客的總結:

數據結構:

type Tree<'a> =  
    | Node of (*data*)'a * (*left*)Tree<'a> * (*right*)Tree<'a>  
    | Leaf 

let tree7 = Node(4, Node(2, Node(1, Leaf, Leaf), Node(3, Leaf, Leaf)),  
                    Node(6, Node(5, Leaf, Leaf), Node(7, Leaf, Leaf)))

二叉樹折疊函數

let FoldTree nodeF leafV tree =   
    let rec Loop t cont =   
        match t with   
        | Node(x,left,right) -> Loop left  (fun lacc ->    
                                Loop right (fun racc ->   
                                cont (nodeF x lacc racc)))   
        | Leaf -> cont leafV   
    Loop tree (fun x -> x) 

例子

let SumNodes = FoldTree (fun x l r -> x + l + r) 0 tree7
let Tree6to0 = FoldTree (fun x l r -> Node((if x=6 then 0 else x), l, r)) Leaf tree7

多路樹版本[不(完全)工作]

數據結構

type MultiTree = | MNode of int * list<MultiTree>

let Mtree7 = MNode(4, [MNode(2, [MNode(1,[]); MNode(3, [])]);  
                    MNode(6, [MNode(5, []); MNode(7, [])])])

折疊功能

let MFoldTree nodeF leafV tree = 
    let rec Loop  tree cont =   
        match tree with   
        | MNode(x,sub)::tail -> Loop (sub@tail) (fun acc -> cont(nodeF x acc))
        | [] -> cont leafV
    Loop  [tree] (fun x -> x) 

示例 1返回 28 - 似乎有效

let MSumNodes = MFoldTree (fun x acc -> x + acc) 0 Mtree7

示例 2

不運行

let MTree6to0 = MFoldTree (fun x acc -> MNode((if x=6 then 0 else x), [acc])) Mtree7

最初我認為MFoldTree需要一個map.something某處,但我讓它與@運算符一起工作。

對第二個示例的任何幫助和/或糾正我在MFoldTree函數中所做的MFoldTree都會很棒!

干杯

杜西奧德

訣竅是你需要傳遞一個額外的函數來折疊。

在 Brian 的版本中, fold 函數只需要使用節點中的值和從左右子樹產生的兩個值調用的nodeF

這對於多路樹來說是不夠的。 在這里,我們需要一個函數nodeF ,該函數使用節點中的值和通過聚合子樹的所有值產生的結果來調用。 但是您還需要一個函數 - 比如combineF ,它結合了從節點的多個子樹產生的值。

您的 fold 函數是一個好的開始——您只需要再添加一個遞歸調用來處理tail

let MFoldTree nodeF combineF leafV tree = 
    let rec Loop trees cont =   
        match trees with   
        | MNode(x,sub)::tail -> 
            // First, process the sub-trees of the current node and get 
            // a single value called 'accSub' representing (aggregated)
            // folding of the sub-trees.
            Loop sub (fun accSub -> 
              // Now we can call 'nodeF' on the current value & folded sub-tree
              let resNode = nodeF x accSub
              // But now we also need to fold all remaining trees that were
              // passed to us in the parameter 'trees'..
              Loop tail (fun accTail ->
                // This produces a value 'accTail' and now we need to combine the
                // result from the tail with the one for the first node 
                // (which is where we need 'combineF')
                cont(combineF resNode accTail) ))
        | [] -> cont leafV
    Loop  [tree] (fun x -> x) 

求和很容易,因為我們只對兩個函數使用+運算符:

let MSumNodes = MFoldTree (+) (+) 0 Mtree7

過濾樹更棘手。 nodeF函數將獲取節點中的元素和子節點列表(即聚合的結果)並生成單個節點。 combineF函數將從第一個節點(即MultiTree值)和從其余節點生成的子節點列表中獲取結果。 從空樹產生的初始值是一個空列表:

let MTree6to0 = 
  MFoldTree (fun x children -> MNode((if x=6 then 0 else x), children)) 
            (fun head tail -> head::tail) [] Mtree7

另一種解決方案可能是

let rec mfold f a (MNode(x,s)) = f (List.fold (fun a t -> mfold f a t) a s) x

實際上,我們可以將樹視為線性結構(折疊它)。

用例

> mfold (+) 0 Mtree7;;
val it : int = 28

filter 和 normal fold 一樣(因為mfold是普通折疊):

> mfold (fun a x -> if x = 6 then a else x + a) 0 Mtree7;;
val it : int = 22

該函數可以是泛型的(如List.foldArray.fold 、... 可以是泛型)。

“但第二個的目的是返回修改后的整個樹,以便任何具有例如值為 6 的節點現在具有值為 0”

但這不是fold計算,而是map

您可以輕松完成(再次將其視為線性結構)

let rec mmap f (MNode(x,s)) = MNode(f x, List.map (mmap f) s)

用例

> mmap (fun x -> if x=6 then 0 else x) Mtree7;;
val it : MultiTree =
  MNode
    (4,
     [MNode (2,[MNode (1,[]); MNode (3,[])]);
      MNode (0,[MNode (5,[]); MNode (7,[])])])

同樣,我建議為每個可能的列表容器( SeqListArray等)執行此操作,它使用戶能夠在上下文中選擇最佳策略。

筆記:

  • 我是 F# 新手,如果有些錯誤,請見諒。
  • 堆棧大小應該不是問題,堆棧級別等於樹的深度。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM