On Aug 27, 4:39 am, Parth Malwankar <[EMAIL PROTECTED]> wrote:
> On Aug 26, 8:25 pm, Parth Malwankar <[EMAIL PROTECTED]> wrote:
>
>
>
> > Hello,
>
> > In order to update fields in nested structures/maps easily
> > I have created a macro 'field-write'.
> >     (defmacro field-write [st k v access-spec]
> >       ; st=data, k=key to update, v=val to put, access-spec=access
> > vector
> >       ; ... code listing after interaction
>
> >     user=> nx
> >     {:a {:b {:c {:content 10}}}}
> >     user=> (field-write nx :content 1000 [:a :b :c])
> >     {:a {:b {:c {:content 1000}}}}
> >     user=> (macroexpand '(field-write nx :content 1000 [:a :b :c]))
> >     (clojure/assoc
> >       nx :a
> >       (clojure/assoc
> >         (clojure/-> nx :a) :b
> >         (clojure/assoc
> >           (clojure/-> nx :a :b) :c
> >           (clojure/assoc
> >             (clojure/-> nx :a :b :c):content 1000))))
>
> > [formatting added above for readability]
>
> > It seems to be working fine but I thought it may be
> > good to get inputs from the Clojure experts here to
> > see if there is a better way to do this in Clojure.
>
> >     (def nx {:a {:b {:c {:content 10}}}})
>
> >     (def field-write)
> >     (defmacro field-write [st k v access-spec]
> >       ; st=data, k=key to update, v=val to put, access-spec=access
> > vector
> >       (if (pred/empty? access-spec)
> >         `(assoc ~st ~k ~v)
> >         (field-write st (last access-spec)
> >                      `(assoc (-> ~st [EMAIL PROTECTED]) ~k ~v)
> >                      (butlast access-spec))))
>
> After some more experimentation I found that the field-write
> macro didn't work with access-specs like (vector :a :b :c)
> ... I should have thought of that before.
>
> So I reimplemented field-read and field-write as functions
> which seem to work in all scenarios.
>
> (defn field-read [st as]
>   "user=> nx
>   {:a {:b {:c {:data 10}}}}
>   user=> (field-read nx [:a :b :c])
>   {:data 10}"
>   (eval (reduce (comp reverse list) st as)))
>
> (defn field-write [structure kwd value access-spec]
>   "user=> nx
>   {:a {:b {:c {:data 10}}}}
>   user=> (field-write nx :data 20 [:a :b :c])
>   {:a {:b {:c {:data 20}}}}
>   user=> (field-write nx :data (+ 2 2 2) (vector :a :b :c))
>   {:a {:b {:c {:data 6}}}}"
>   (loop [st structure
>             k kwd
>             v value
>             as access-spec]
>     (if (pred/empty? as)
>       (assoc st k v)
>       (recur st (last as)
>              (assoc (field-read st as) k v)
>              (butlast as)))))
>
> I suspect using eval in field-read is a bad idea (preformance?) but I
> couldn't come up with a better way to do it. access-spec
> needs to be a vector as its something thats returned by
> another function in my use case (otherwise I could have
> used it with ->).
>
> Can I do something better here? Comments?
>

I posted a variant here:

http://paste.lisp.org/display/65964

Rich

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to