Clojure Struktur nestet i en annen struktur

stemmer
6

Er det mulig å ha en struktur nestet innenfor en struktur i Clojure? Vurdere følgende kode:

(defstruct rect :height :width)
(defstruct color-rect :color (struct rect))

(defn 
#^{:doc Echoes the details of the rect passed to it}
echo-rect
[r]
  (println (:color r))
  (println (:height r))
  (println (:width r)))

(def first-rect (struct rect 1 2))
;(def c-rect1 (struct color-rect 249 first-rect)) ;form 1
;output 249 nil nil
(def c-rect1 (struct color-rect 249 1 2)) ;form 2
;output Too many arguments to struct constructor

(echo-rect c-rect1)

Dette er selvfølgelig en contrived eksempel, men det finnes tilfeller der jeg ønsker å bryte en stor datastruktur i mindre understell gjøre koden enklere å vedlikeholde. Som kommentarene vise om jeg gjør skjema 1 får jeg 249 nil nil, men hvis jeg gjør skjema 2 jeg får For mange argumenter for å struct konstruktøren.

Hvis jeg nærmer dette problemet på feil måte, kan du fortelle meg hva jeg skal gjøre. Søke på Clojure google gruppen ikke slå opp noe for meg.


Redigere:

Jeg tror jeg var ikke så klart i uttalelsen på spørsmålet mitt som jeg trodde jeg var:

1.) Er det mulig å hekke en struct innenfor hverandre i Clojure? (Ut fra under det er et ja.)

2.) Hvis ja, hva ville være riktig syntaks være? (Igjen, vi dømme ut fra under det ser ut som det er noen måter man kan gjøre dette.)

3.) Hvordan hente en verdi vet av en bestemt tast når du har fått en struct nestet i en annen struct?

Jeg tror min eksempelkode gjorde egentlig ikke demonstrere hva jeg prøvde å gjøre det veldig bra. Jeg legger dette her slik at andre som søker etter dette kan finne dette spørsmålet og dets svar lettere.

Publisert på 16/02/2009 klokken 23:23
kilden bruker
På andre språk...                            


5 svar

stemmer
7

Jeg er enig med andre plakater i at struct maps egentlig ikke støtter arv. Men hvis du ønsker å bare lage en ny struct som bruker nøklene til en annen, vil dette arbeidet:

; Create the rect struct
(defstruct rect :height :width)

; Create the color-rect using all the keys from rect, with color added on
(def color-rect (apply create-struct (cons :color (keys (struct rect)))))

(defn create-color-rect 
  "A constructor function that takes a color and a rect, or a color height and width"
  ([c r] (apply struct (concat [color-rect c] (vals r))))
  ([c h w] (struct color-rect c h w)))

Du trenger ikke echo-rectfunksjonen, kan du rett og slett vurdere struct kartet omgang å se hva som er i det:

user=> (def first-rect (struct rect 1 2))
#'user/first-rect
user=> first-rect
{:height 1, :width 2}
user=> (create-color-rect 249 first-rect)
{:color 249, :height 1, :width 2}
user=> (create-color-rect 249 1 2)
{:color 249, :height 1, :width 2}
Svarte 17/02/2009 kl. 14:03
kilden bruker

stemmer
6

Du kan lage en struct være en verdi av en annen struct hvis du gir det en nøkkel til å bli assosiert med. Du kan gjøre det som nedenfor.

(Det kan enkelt få tilgang tarmene til vilkårlig nestet hasher / structs via ->, som en bit av syntaks sukker).

(defstruct rect :height :width)
(defstruct color-rect :rect :color)

(def cr (struct color-rect (struct rect 1 2) :blue))
;; => {:rect {:height 1, :width 2}, :color :blue}

(:color cr)           ;; => :blue
(:width (:rect cr))   ;; => 2
(-> cr :color)        ;; => :blue
(-> cr :rect :width)  ;; => 2
Svarte 18/02/2009 kl. 19:59
kilden bruker

stemmer
6

Hekkende strukturer er mulig og noen ganger ønskelig. Imidlertid ser det ut som du prøver å gjøre noe annerledes: Det ser ut som du prøver å bruke arv av strukturtyper i stedet for komposisjon. Det er, i skjema 2 du oppretter en farge-rect som inneholder en rect men du prøver å konstruere en forekomst som om det var en rect. Form 1 verk fordi du konstruere c-rect1 fra en pre-eksisterende rect, som er den riktige måten å bruke komposisjon.

Et raskt søk på Clojure gruppe eller bare på nettet generelt bør lede deg til en god beskrivelse av skillet mellom komposisjon og arv. I Clojure, sammensetning eller duck-typing (se Google igjen) er nesten alltid foretrukket å arv.


Redigere:

Som svar på ditt spørsmål nr 3: Et alternativ til å bruke -> for å trekke ut data i nestede strukturer, som Brian Carper beskrevet i sitt svar, er å få inn, sammen med sine søsken tilkn-i og oppdatering-in:

For eksempel:

(def cr {:rect {:height 1, :width 2}, :color :blue})
(get-in cr [:rect :width])
;; => 2

(assoc-in cr [:rect :height] 7)
;; => {:rect {:height 7, :width 2}, :color :blue}

(update-in cr [:rect :width] * 2)
;; => {:rect {:height 1, :width 4}, :color :blue}

(assoc-in cr [:a :new :deeply :nested :field] 123)
;; => {:a {:new {:deeply {:nested {:field 123}}}}, 
;;     :rect {:height 1, :width 2}, :color :blue}
Svarte 17/02/2009 kl. 00:04
kilden bruker

stemmer
1

Jeg skjønner at dette er en gammel spørsmålet nå, men jeg kom opp med følgende makro:

(defmacro extendstruct [n b & k]
  `(def ~n
    (apply create-struct
      (clojure.set/union
        (keys (struct ~b))
        #{~@k}))))

Som ville tillate deg å skrive dette:

(defstruct rect :width :height)
(extendstruct color-rect rect :color)

testing:

(struct rect)       ; {:width nil, :height nil}
(struct color-rect) ; {:color nil, :width nil, :height nil}

Vil dette være noe passende?

Det kan også modifiseres slik at en samling av strukturer vil kunne anvendes. Eller enda kan du bruke andre struct definisjoner som navnene på taster som er automatisk utvidet til tastene produsert av en slik struct:

(defstructx one :a :b)
(defstructx two :c one :d)
(defstructx three :e two :f :g)
; three
(keys (struct three)) ; #{:e :c :a :b :d :f :g}
Svarte 20/11/2011 kl. 00:57
kilden bruker

stemmer
1

Jeg er veldig ny i Clojure, så jeg kan være galt. Men jeg tror, ​​kan du ikke gjøre noe sånt

(defstruct color-rect :color (struct rect))

Så vidt jeg forstår Clojure-structs, vil dette skape et struct (i utgangspunktet et kart med kjente taster), som har en eller annen måte struct 'rect' som en av sine nøkler.

Min antakelse er støttet av den observasjon at en enkel evaluering av (struct rect) gir

{:height nil, :width nil}

Mens en evaluering av (struct farge-rect) tilveiebringer:

{:color nil, {:height nil, :width nil} nil}

EDIT: Hva kan hjelpe deg er det faktum at structs ikke er begrenset til tastene, de er definert med. Det ser ut som om du kunne oppnå, hva du prøver med noe sånt som dette:

(def c-rect1 (struct-map color-rect :color 249 :height 1 :width 1 )) ;form 3
Svarte 17/02/2009 kl. 00:01
kilden bruker

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more