एक कार्यक्रम से 'वनों की कटाई' 'पेड़ों' को कैसे हटाता है?


12

मुझे लगता है कि यह समझ में आता है कि वनों की कटाई कैसे होती है और एक ही समय में एक सूची बनाता है (एक गुना और एक अनपेक्षित कार्य से - कोडरव्यू पर इस अच्छे उत्तर को यहां देखें ), लेकिन जब मैंने तुलना की कि तकनीक पर विकिपीडिया प्रविष्टि के साथ इसे हटाने के बारे में बात की थी एक कार्यक्रम से पेड़ '।

मैं समझता हूं कि कैसे एक प्रोग्राम को एक वाक्यात्मक पार्स ट्री (क्या यह सही है?) में पार्स किया जा सकता है, लेकिन कुछ प्रकार के सरलीकरण (क्या यह है?) के लिए वनों की कटाई के इस उपयोग का क्या अर्थ है? और मैं इसे अपने कोड में कैसे करूंगा?

जवाबों:


9

Yatima2975 को लगता है कि आपने अपने पहले दो प्रश्नों को कवर कर लिया है, मैं तीसरे को कवर करने की कोशिश करूँगा। ऐसा करने के लिए मैं एक अनुचित रूप से सरल मामले का इलाज करूंगा, लेकिन मुझे यकीन है कि आप कुछ अधिक यथार्थवादी कल्पना कर पाएंगे।

n

type Tree = Leaf | Node Tree Tree

n

full : Int -> Tree
full n | n == 0 = Leaf
full n = Node (full (n-1)) (full (n-1))

और एक पेड़ की गहराई की गणना होती है

depth : Tree -> Int
depth Leaf = 0
depth (Node t1 t2) = 1 + max (depth t1) (depth t2)

depth (full n)nfulldepthdepth (full n)full_depth

full_depth : Int -> Int
full_depth n | n == 0 = 0
full_depth n = 1 + max (full_depth (n-1)) (full_depth (n-1))

यह पूर्ण पेड़ की स्मृति आवंटन से बचा जाता है, और पैटर्न मिलान करने की आवश्यकता होती है, जो प्रदर्शन में सुधार करता है। इसके अलावा, यदि आप अनुकूलन जोड़ते हैं

max t t --> t

full_depth

केवल मुख्य धारा संकलक जो स्वचालित वनों की कटाई करता है वह जीएचसी है, और अगर मुझे सही ढंग से याद है, तो यह केवल अंतर्निहित कार्यों (तकनीकी कारणों से) की रचना करते समय किया जाता है ।


सम्मानित किया गया क्योंकि मुझे यह जवाब उस तरह से मिला, जिस तरह से यह अन्य उत्तरों से तैयार किया गया था, भले ही वे अनिवार्य रूप से एक ही क्षेत्र को कवर करते हों।
क्राइस स्ट्रिंगफेलो

6

सबसे पहले, सूची एक प्रकार के पेड़ हैं। यदि हम किसी सूची को एक लिंक्ड सूची के रूप में दर्शाते हैं , तो यह सिर्फ एक पेड़ है जिसके प्रत्येक नोड में 1 या 0 वंशज हैं।

पार्स ट्री केवल डेटा संरचना के रूप में पेड़ों का उपयोग है। कंप्यूटर विज्ञान में पेड़ों के कई अनुप्रयोग हैं, जिनमें छंटाई, नक्शे को लागू करना, साहचर्य सरणियाँ आदि शामिल हैं।

सामान्य तौर पर, सूची, पेड़ आदि पुनरावर्ती डेटा संरचनाएं हैं: प्रत्येक नोड में कुछ जानकारी और समान डेटा संरचना का एक और उदाहरण होता है। तह ऐसे सभी संरचनाओं पर एक ऑपरेशन है जो पुनरावर्ती रूप से नोड्स को "नीचे ऊपर" मानों में बदल देता है। अनफॉल्डिंग रिवर्स प्रक्रिया है, यह मानों को "टॉप डाउन" नोड में परिवर्तित करता है।

किसी दिए गए डेटा संरचना के लिए, हम यंत्रवत् उनके तह और खुलासा कार्यों का निर्माण कर सकते हैं।

एक उदाहरण के रूप में, चलो सूची लेते हैं। (मैं इसे टाइप किया गया उदाहरण के लिए हास्केल का उपयोग करूंगा और इसका सिंटैक्स बहुत साफ है।) सूची या तो एक अंत या एक मूल्य और एक "पूंछ" है।

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)यह आइसोमॉर्फिक है 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

)

मैं विवरण छोड़ दूँगा, मुझे आशा है कि पैटर्न स्पष्ट है।

यह सभी देखें:


शानदार जवाब, धन्यवाद। लिंक, और विस्तृत उदाहरण मूल्यवान हैं।
क्राइस स्ट्रिंगफेलो

3

यह थोड़ा भ्रामक है, लेकिन मध्यवर्ती पेड़ों को हटाने के लिए वनों की कटाई (संकलित समय पर) लागू की जाती है जो (रनिंग में) बनाई जाएगी। वनों की कटाई में सार सिंटैक्स ट्री के कुछ हिस्सों को हैक करना शामिल नहीं है (यह मृत शाखा उन्मूलन है :-)

एक और बात यह है कि आप समय उतार फेंका गया हो सकता है कि सूचियों है कर रहे हैं पेड़ सिर्फ बहुत असंतुलित हैं,!


आह येस। बहुत असंतुलित!
संकट स्ट्रींगफेलो
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.