2017-02-15 5 views
6

मुझे कोई रिकर्सिव इकाई स्पेक करने का कोई उदाहरण नहीं मिला है जैसा कि मैं नीचे प्रयास कर रहा हूं। मुझे एहसास है कि ::left और ::right विफल हो रहे हैं क्योंकि उन्हें अभी तक परिभाषित नहीं किया गया है, इसलिए मैं सोच रहा हूं कि मैं उन्हें ::node spec में दोबारा परिभाषित कैसे कर सकता हूं।रिकर्सिव इकाई spec

(s/def ::key string?) 
(s/def ::value string?) 
(s/def ::left ::node) 
(s/def ::right ::node) 
(s/def ::n int?) 
(s/def ::node (s/keys :req [::key ::value ::n] 
         :opt [::left ::right])) 

(defn test-it [] 
    (s/valid? ::node 
      {::key "hi" 
      ::value "bye" 
      ::n 0 
      ::left {::key "what" 
        ::value "nothing" 
        ::n 0} 
      ::right {::key "hello" 
         ::value "goodbye" 
         ::n 0} 
      })) 
+0

यह मेरे लिए लग रहा है जैसे कि यह शिकायत है कि ':: node' में निर्धारित नहीं है ':: बाएं', और' :: दाएं 'की परिभाषाएं, ताकि आप उन दोनों के सामने' :: नोड 'को परिभाषित करने का प्रयास कर सकें। –

+1

@ सैम एस्टेप: फिर आपको एक ही समस्या होगी, क्योंकि ':: नोड' को ':: बाएं' और ':: दाएं' के संदर्भ में परिभाषित किया गया है, जिसे अभी तक परिभाषित नहीं किया जाएगा। क्लोजर में 'घोषणा' की तरह एक सर्किट ब्रेकर की आवश्यकता होती है। –

+1

@ChrisMurphy नहीं, यह ':: नोड' के बाद परिभाषित' :: बाएं 'और ':: दाएं' के साथ ठीक काम करता है। एक चिपकाया आरईपीएल सत्र के लिए मेरा जवाब देखें। –

उत्तर

1

है आप छोड़ दिया क्या नहीं कर रहे हैं और सही संस्थाओं, लेकिन दो नोड्स एक समान तरह से परिभाषित, और दुर्भाग्य से आप नक्शे में ही नाम के दो चाबियाँ नहीं हो सकता है, के बाद से कल्पना की अनुमति नहीं है "अलियासिंग एक कीवर्ड के लिए एक spec के लिए, लेकिन इसके बजाय spec की पहचान करने के लिए कीवर्ड का उपयोग करता है।

एक विकल्प, यदि आप इच्छुक हैं, तो एक ::children कुंजी के संदर्भ में बाएं और दाएं नोड को परिभाषित करना है, जो एक (या दो) दो ::node एस का संग्रह है।

(s/def ::key string?) 
(s/def ::value string?) 
(s/def ::n int?) 

(s/def ::node (s/keys :req [::key ::value ::n])) 
(s/def ::children (s/coll-of ::node :count 2)) 
;; for 1 or 2 children: (s/coll-of ::node :min-count 1 :max-count 2) 

(s/valid? ::node 
    {::key "parent-1" ::value "parent-1" ::n 1 
    ::children [{::key "leaf-1" ::value "leaf-1" ::n 2} 
       {::key "parent-2" ::value "parent-2" ::n 3 
       ::children [{::key "leaf-2" ::value "leaf-2" ::n 4} 
          {::key "leaf-3" ::value "leaf-3" ::n 5}]}]}) 

यह आपको एक समान संरचना प्रदान करता है, एक वेक्टर दो नोड्स के बजाय दो चाबियाँ, एक नोड के साथ प्रत्येक युक्त मामूली अतिरिक्त जटिलता के साथ।

एक अन्य विकल्प है कि विशुद्ध रूप से खुद के मामले में एक परिभाषा के लिए अनुमति देता है एक नक्शा संरचना त्याग और इसके बदले एक नेस्टेड वेक्टर करना है:

(s/def ::node (s/or :parent (s/coll-of ::node :count 2) 
        :leaf (s/tuple ::key ::value ::n))) 

(s/valid? ::node 
    [[[["a" "a" 1] 
    ["b" "b" 2]] 
    ["c" "c" 3]] 
    ["d" "d" 4]]) 

यह काम करता है क्योंकि तत्वों अनुक्रमिक हैं और के साथ जुड़े होने की जरूरत नहीं एक अनूठी कुंजी, जैसा ऊपर नक्शा संरचना में है (हां, वैक्टर भी सहयोगी हैं, लेकिन इस क्रम में उनकी अनुक्रमिक प्रकृति का उपयोग किया जा रहा है)। यह स्वीकार्य रूप से "साफ" नहीं है, और पहली विधि शायद पसंद की जाती है, लेकिन यह एक विकल्प है यदि आप सहयोगी संरचना से गुजरना चाहते हैं और इसे अनुक्रमिक के लिए व्यापार करना चाहते हैं।

2

यह काम करता है यदि आप ::left और ::right::node से नीचे की परिभाषाओं को हल करते हैं, जैसा सैम एस्टेप द्वारा प्रश्न पर टिप्पणी में सुझाया गया है; s/keys में संदर्भ तुरंत बाद नहीं किया जाएगा:

Clojure 1.9.0-alpha14 
user=> (require '[clojure.spec :as s]) 
nil 
user=> (s/def ::key string?) 
:user/key 
user=> (s/def ::value string?) 
:user/value 
user=> (s/def ::n int?) 
:user/n 
(s/def ::node (s/keys :req [::key ::value ::n] 
         :opt [::left ::right])) 
:user/node 
user=> (s/def ::left ::node) 
:user/left 
user=> (s/def ::right ::node) 
:user/right 
(defn test-it [] 
    (s/valid? ::node 
      {::key "hi" 
      ::value "bye" 
      ::n 0 
      ::left {::key "what" 
        ::value "nothing" 
        ::n 0} 
      ::right {::key "hello" 
         ::value "goodbye" 
         ::n 0} 
      })) 
#'user/test-it 
user=> (test-it) 
true 
user=> (s/valid? ::node {::key "hi" ::value "bye" ::n 0 ::left {}}) 
false 
2

के विपरीत नियमित def रों, s/def रों को छोड़कर जब आप उर्फ ​​(s/def ::a ::b) जहां ::b::a से पहले परिभाषित किया जाना चाहिए घोषणा ... के आदेश पर निर्भर नहीं हैं।

तो या तो आप अपने s/def रों के रूप में मीकल ने सुझाव दिया है या आप (s/and) में दाएँ हाथ के मूल्य लपेट को पुन: व्यवस्थित:

(s/def ::key string?) 
(s/def ::value string?) 
(s/def ::left (s/and ::node)) 
(s/def ::right (s/and ::node)) 
(s/def ::n int?) 
(s/def ::node (s/keys :req [::key ::value ::n] 
         :opt [::left ::right])) 

(defn test-it [] 
    (s/valid? ::node 
      {::key "hi" 
      ::value "bye" 
      ::n 0 
      ::left {::key "what" 
        ::value "nothing" 
        ::n 0} 
      ::right {::key "hello" 
         ::value "goodbye" 
         ::n 0} 
      })) 
संबंधित मुद्दे