2016-10-05 8 views
6

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

एक गैर-अपरिवर्तनीय भाषा में, मैं बस उस वस्तु का एक मूल्य बदल दूंगा, और यही वह है, लेकिन यह एल्म जैसी अपरिवर्तनीय भाषा में काफी मुश्किल है।

type alias Item = 
    { id: String 
    , text: String 
    , children: ChildItems 
    } 

type ChildItems = ChildItems (List Item) 

type alias Model = 
    { rootItem: Item 
    } 

updateItem: Item -> Item -> Item 
updateItem: rootItem item = 
    -- TODO 

... 

update model = 
    case msg of 
    UpdateItem item updatedText -> 
     let 
     updatedItem = { item | text = updatedText } 
     in 
     ({ model | rootItem = (updateItem model.rootItem updatedItem) }, Cmd.none) 
इस

क्या मैं

updateItem: Item.Item -> Item.Item -> Item.Item 
updateItem rootItem updatedItem = 
    if rootItem.id == updatedItem.id then 
    updatedItem 
    else 
    case rootItem.children of 
     Item.ChildItem [] -> 
     rootItem 

     Item.ChildItem children -> 
     let 
      updatedChildren = 
      case children of 
       [] -> 
       [] 

       children -> 
       List.map (\item -> 
        updateItem rootItem item) children 
     in 
      { rootItem | children = Item.ChildItem updatedChildren } 

के साथ आया है, लेकिन मैं एक Maximum call stack size exceeded त्रुटि

उत्तर

15

कारण आप ढेर अतिप्रवाह हो रही है हो रही है क्योंकि आप rootItem बजाय लौट रहे हैं []Item.ChildItems [] मामले में।

मैं आपके कोड को थोड़ा सा संशोधित करने जा रहा हूं क्योंकि कुछ सामान्य पैटर्न हैं जिन्हें हम बाहर खींच सकते हैं। सबसे पहले, की अंतर्निहित पेड़-ish संरचना लेने के लिए और है कि अधिक सामान्य बनाना इतना है कि यह, बात किसी भी प्रकार फिट सकता मत सिर्फ Item:

type Node a 
    = Node a (List (Node a)) 

हमें एक संरचना हमेशा एक रूट नोड है कि देता है कि और इसमें कई बच्चे हो सकते हैं, जिनमें से प्रत्येक के पास भी कई बच्चे हो सकते हैं।

यदि हम आपके द्वारा जा रहे एल्गोरिदम के बारे में सोचते हैं, तो हम एक परिचित पैटर्न को बाहर निकाल सकते हैं। आपके पास कई वस्तुओं के साथ एक संरचना है और आप एक एल्गोरिदम चाहते हैं जो प्रत्येक आइटम पर जाता है और वैकल्पिक रूप से इसे बदल देता है। यह List.map जैसा लगता है। यह इस तरह के एक आम मुहावरा है कि यह एक अच्छा विचार है हमारे सामान्यीकृत समारोह map कॉल करने के लिए:

map : (a -> b) -> Node a -> Node b 
map f (Node item children) = 
    Node (f item) (List.map (map f) children) 

(साइड नोट: हम यह सिर्फ functors में ठोकर खाई है!)

जब से मैं विचार कर लिया है

type alias Item = 
    { id: String 
    , text: String 
    } 

अब जब हम एकहै: बच्चों की और यह Node प्रकार में रखा है, हम तो जैसे उर्फ ​​Item संशोधित करने की आवश्यकता, यह एक ऐसा फ़ंक्शन रखना सहायक होगा जो इसे अपडेट कर सकता है यदि id किसी निश्चित मान से मेल खाता है।

updateByID : String -> (Item -> Item) -> Item -> Item 
updateByID id f item = 
    if item.id == id then 
    f item 
    else 
    item 

अब एक पर एक अद्यतन प्रदर्शन करने के लिए: चूंकि भविष्य में, आप और अधिक अद्यतन कार्यों, जो आप चाहते हो सकता है, यह देखने और आईडी मिलान भाग समारोह से अलग रखना आप वास्तव में प्रदर्शन करने के लिए चाहता हूँ सबसे अच्छा है आईडी से मेल खाने वाली वस्तु, पेड़ के भीतर कहीं भी, आप बस यह कर सकते हैं:

map (updateByID "someID" (\x -> { x | text = "Woohoo!" })) rootNode 
+0

उत्कृष्ट उत्तर! आपने मेरा दिन बनाया है :) –

+0

मैं इस पैटर्न का उपयोग कर आइटम की नेस्टेड सूची कैसे अपडेट करूं? समस्या जो मैं मार रहा हूं वह यह है कि रिकॉर्ड अपडेट अभिव्यक्ति को किसी भी फ़ंक्शन की वापसी अभिव्यक्ति के रूप में डिज़ाइन किया गया है। मैं एक नया आइटम बनाने के लिए डिज़ाइन किया गया फ़ंक्शन, वापसी अभिव्यक्ति नया आइटम होना चाहिए, आइटम की नहीं माता-पिता की बच्चों की सूची, जो मुझे अद्यतन करने की आवश्यकता है। क्या हमारे पास रिकर्सिव (उर्फ "पेड़") संरचनाओं से निपटने के तरीके पर शास्त्र है? मैंने आइटम को एक प्रकार के उपनाम और संग्रह को एक प्रकार बनाने के निर्देश देखे हैं; आप एक अलग प्रोटोकॉल की पेशकश करते हैं। –

+0

@ रिचर्डहेवन जिसे मानचित्र फ़ंक्शन द्वारा संभाला जाता है - ध्यान दें कि उसके शरीर में यह नोड से आइटम से बना नोड बनाता है, जिसे संभवतः फ़ंक्शन द्वारा संशोधित किया गया था, और नोड के बच्चों को यह दिया गया था, प्रत्येक भी संभवतः समारोह द्वारा संशोधित। आखिरकार जब अद्यतन करने के लिए मानचित्र में अद्यतन किया जाता है तो यह एक ही टुकड़े का उपयोग करके नोड्स के पेड़ को फिर से बना देगा, जो एक आइटम को बदल दिया गया है। –

संबंधित मुद्दे