ก่อนรายการเป็นชนิดของต้นไม้ หากเราแสดงรายการเป็นรายการที่เชื่อมโยงมันเป็นเพียงทรีที่แต่ละโหนดมีลูกหลาน 1 หรือ 0 คน
แยกวิเคราะห์ต้นไม้เป็นเพียงการใช้ประโยชน์ของต้นไม้เป็นโครงสร้างข้อมูล ต้นไม้มีแอปพลิเคชั่นมากมายในสาขาวิทยาศาสตร์คอมพิวเตอร์รวมถึงการเรียงลำดับการนำแผนที่ไปใช้อาเรย์แบบเชื่อมโยง ฯลฯ
โดยทั่วไปรายการต้นไม้ ฯลฯ เป็นโครงสร้างข้อมูลแบบเรียกซ้ำ: แต่ละโหนดมีข้อมูลบางส่วนและอินสแตนซ์อื่นของโครงสร้างข้อมูลเดียวกัน การพับคือการดำเนินการกับโครงสร้างดังกล่าวทั้งหมดที่แปลงโหนดเป็นค่า "bottom up" แบบวนซ้ำ การแฉเป็นกระบวนการย้อนกลับจะแปลงค่าเป็นโหนด "จากบนลงล่าง"
สำหรับโครงสร้างข้อมูลที่กำหนดเราสามารถสร้างฟังก์ชั่นการพับและการแฉกลไกได้
ตัวอย่างเช่นลองทำรายการ (ฉันจะใช้ Haskell เพื่อเป็นตัวอย่างในขณะที่พิมพ์และไวยากรณ์ของมันสะอาดมาก) รายการอาจเป็นจุดสิ้นสุดหรือค่าและ "ส่วนท้าย"
data List a = Nil | Cons a (List a)
สมมติว่าเรากำลังพับรายการ ในแต่ละขั้นตอนเรามีโหนดปัจจุบันที่จะพับและเราได้พับโหนดย่อยซ้ำแล้วซ้ำอีก เราสามารถแสดงสถานะนี้เป็น
data ListF a r = NilF | ConsF a r
โดยที่rเป็นค่ากลางที่สร้างขึ้นโดยการพับรายการย่อย สิ่งนี้ทำให้เราสามารถแสดงฟังก์ชั่นการพับบนรายการ:
foldList :: (ListF a r -> r) -> List a -> r
foldList f Nil            = f NilF
foldList f (Cons x xs)    = f (ConsF x (foldList f xs))
เราแปลงListเข้าไปโดยซ้ำพับมากกว่ารายการย่อยและจากนั้นใช้ฟังก์ชั่นที่กำหนดไว้ในListF ListFหากคุณคิดเกี่ยวกับสิ่งนี้นี่เป็นเพียงการนำเสนอมาตรฐานอื่นfoldr:
foldr :: (a -> r -> r) -> r -> List a -> r
foldr f z = foldList g
  where
    g NilF          = z
    g (ConsF x r)   = f x r
เราสามารถสร้างunfoldListในแบบเดียวกัน:
unfoldList :: (r -> ListF a r) -> r -> List a
unfoldList f r = case f r of
                  NilF        -> Nil
                  ConsF x r'  -> Cons x (unfoldList f r')
อีกครั้งมันเป็นเพียงการเป็นตัวแทนของunfoldr:
unfoldr :: (r -> Maybe (a, r)) -> r -> [a]
(ขอให้สังเกตว่าMaybe (a, r)isomorphic ถึงListF a r)
และเราสามารถสร้างฟังก์ชั่นการตัดไม้ทำลายป่าด้วย:
deforest :: (ListF a r -> r) -> (s -> ListF a s) -> s -> r
deforest f u s = f (map (deforest f u) (u s))
  where
    map h NilF        = NilF
    map h (ConsF x r) = ConsF x (h r)
มันแยกกลางListและผสมฟังก์ชั่นการพับและการคลี่เข้าด้วยกันอย่างง่ายดาย
ขั้นตอนเดียวกันสามารถนำไปใช้กับโครงสร้างข้อมูลแบบเรียกซ้ำ ตัวอย่างเช่นต้นไม้ที่มีโหนดสามารถมี 0, 1, 2 หรือลูกหลานที่มีค่าในโหนด 1- หรือ 0 สาขา:
data Tree a = Bin (Tree a) (Tree a) | Un a (Tree a) | Leaf a
data TreeF a r = BinF r r | UnF a r | LeafF a
treeFold :: (TreeF a r -> r) -> Tree a -> r
treeFold f (Leaf x)       = f (LeafF x)
treeFold f (Un x r)       = f (UnF x (treeFold f r))
treeFold f (Bin r1 r2)    = f (BinF (treeFold f r1) (treeFold f r2))
treeUnfold :: (r -> TreeF a r) -> r -> Tree a
treeUnfold f r = case f r of
                  LeafF x         -> Leaf x
                  UnF x r         -> Un x (treeUnfold f r)
                  BinF r1 r2      -> Bin (treeUnfold f r1) (treeUnfold f r2)
แน่นอนเราสามารถสร้างdeforestTreeกลไกได้เหมือนเมื่อก่อน
(โดยปกติเราจะแสดงtreeFoldความสะดวกมากขึ้นเช่น:
treeFold' :: (r -> r -> r) -> (a -> r -> r) -> (a -> r) -> Tree a -> r
)
ฉันจะออกจากรายละเอียดฉันหวังว่ารูปแบบที่ชัดเจน
ดูสิ่งนี้ด้วย: