2017-02-15 24 views
6

Aşağıda, denemeye çalıştığım gibi özyinelemeli bir özellik nasıl yapılacağına dair bir örnek bulamadım. ::left ve ::right öğelerinin henüz tanımlı olmadıkları için başarısız olduklarını fark ettim, dolayısıyla bunları ::node spesifikasyonunda yinelemeli olarak nasıl tanımlayabildiğimi merak ediyorum.Özyinelelik özelliği

(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

'' left' ve ':: right' tanımları, bu yüzden bu ikiden önce' :: node 'tanımlamayı denemek isteyebilirsiniz. –

+1

@Sam Estep: O zaman aynı soruna sahip olursunuz, çünkü ':: node' henüz tanımlanamayan ':: left' ve' :: right' terimleriyle tanımlanır. Clojure'da "declare" gibi bir devre kesici gereklidir. –

+1

@ChrisMurphy Hayır, '' node'dan sonra '' left' ve '' right' tanımlı '' left' ile iyi çalışır. Yapıştırılan bir REPL oturumu için yanıtımı gör. –

cevap

1

sol ve sağ kişiler, ancak Spec izin vermez, çünkü iki düğüm özdeş biçimde tanımlanmış ve ne yazık ki haritanın aynı ada sahip iki anahtar olamaz değil var ne "örtüşme "bir anahtar kelimeye ait bir özellik değil, bunun yerine söz konusu özellikleri belirlemek için anahtar kelimenin kendisini kullanır. Eğer istekli iseniz

Seçeneklerden biri, (bir ya da) iki ::node s topluluğudur tek ::children anahtarı açısından sağ ve sol düğümleri tanımlamaktır.

(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}]}]}) 

Bu iki düğüm, yerine iki anahtar, bir düğüm ile her biri bir vektörün hafif bir ilave komplekslik ile, benzer bir yapı verir.

tamamen kendisi açısından bir belirleme sağlayan bir diğer seçenek bir harita yapısını vazgeçmek ve bunun yerine iç içe bir vektör yapmaktır

:

(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]]) 

elemanları sıralı ve ilişkili gerekmez, çünkü bu işleri Yukarıdaki harita yapısında olduğu gibi benzersiz bir anahtar (evet, vektörler aynı zamanda birleştirici niteliktedir, ancak bu durumda sıralı nitelikleri kullanılmaktadır). Bu kabul edilebilir bir şekilde "temiz" değildir ve ilk yöntem muhtemelen tercih edilir, ancak birleştirici yapıdan vazgeçmek ve sıralı bir ürün için ticaret yapmak istiyorsanız bir seçenektir.

soruya yaptığı yorumda Sam ESTEP önerdiği gibi, ::node altına ::left ve ::right tanımlarını Taşırsanız çalışır
2

; s/keys referanslar hemen ardından olmayacak:

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

düzenli def s aksine, s/def s takma (s/def ::a ::b)::b::a önce tanımlanmış olmalıdır nerede dışında beyanı ... sırasına bağlı değildir. Michał önerdiği ya da (s/and) sağ taraftaki değeri sarın olarak

Yani ya sen senin s/def s yeniden düzenlemek: :: node` tanımlı değil `şikayet gibi içeriye bana bakar

(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} 
      })) 
İlgili konular