Was haben Sie nicht links und rechts Entitäten, sondern zwei Knoten in gleicher Art und Weise definiert, und leider kann man zwei Schlüssel nicht in der Karte mit dem gleichen Namen hat, da spec nicht erlaubt „Aliasing "von einem Schlüsselwort zu einer Spezifikation, sondern stattdessen das Schlüsselwort selbst, um die Spezifikation zu identifizieren.
Eine Möglichkeit, wenn Sie wollen, ist die Definition der linken und rechten Knoten in Bezug auf einen einzigen Schlüssel , die eine Sammlung von (ein oder zwei) ::node
s ist.
(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}]}]})
Dies gibt Ihnen eine ähnliche Struktur, mit der geringen zusätzlichen Komplexität eines Vektors zwei Knoten enthält, anstelle von zwei Tasten, die jeweils mit einem Knoten.
Eine weitere Option, die für eine Definition rein in Bezug auf sich selbst erlaubt ist, eine Map-Struktur, zu verzichten und eine verschachtelte Vektor stattdessen tun:
(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]])
Das funktioniert, weil die Elemente sequentiell sind und nicht mit in Verbindung gebracht werden müssen ein eindeutiger Schlüssel, wie in der obigen Kartenstruktur (ja, Vektoren sind auch assoziativ, aber ihre sequentielle Natur wird in diesem Fall verwendet). Dies ist zugegebenermaßen nicht so "sauber", und die erste Methode wird wahrscheinlich bevorzugt, aber es ist eine Option, wenn Sie bereit sind, auf die assoziative Struktur zu verzichten und sie für eine sequentielle zu tauschen.
Es sieht für mich wie es beschwert sich, dass ':: node' nicht in definiert ist, die Definitionen von ':: left' und' :: right', also sollten Sie versuchen, '' node' 'vor diesen beiden zu definieren. –
@Sam Estep: Dann hätten Sie das gleiche Problem, weil ':: node' in' 'left'' und' 'right'' definiert ist, was noch nicht definiert ist. Ein Leistungsschalter wird benötigt, wie zum Beispiel 'declare' in Clojure. –
@ChrisMurphy Nein, es funktioniert gut mit ':: left' und' :: right' definiert nach ':: node'. Siehe meine Antwort für eine eingefügte REPL-Sitzung. –