macros - Backquote without parens -


i working through excellent book let on lambda, , trying port common lisp code defunits on clojure.

the following generates macro supposed take

(defn defunits-chaining [u units prev]   (if (some #(= u %) prev)     (throw (throwable. (str u " depends on " prev))))   (let [spec (first (filter #(= u (first %)) units))]     (if (nil? spec)       (throw (throwable. (str "unknown unit " u)))       (let [chain (second spec)]         (if (list? chain)           (* (first chain)              (defunits-chaining                (second chain)                units                (cons u prev)))           chain)))))  (defmacro defunits [quantity base-unit & units]   `(defmacro ~(symbol (str "unit-of-" quantity))      [valu# un#]      `(* ~valu#          ~(case un#            ~base-unit 1             ~@(map (fn [x]                      `(~(first x)               ;; <-- pretty sure it's `(                        ~(defunits-chaining                           (first x)                           (cons `(~base-unit 1)                                 (partition 2 units))                           nil)))                    (partition 2 units))))))  (defunits time s m 60 h 3600) 

and turn macro can called like

(unit-of-time 4 h) 

and give results in base unit (seconds in case). think problem clojure/cl api change in "case". "case" in cl looks this:

(case 'a (('b) 'no) (('c) 'nope) (('a) 'yes)) 

but in clojure...

(case 'a 'b 'no 'c 'nope 'a 'yes) 

how convenient. changed anon function in nested defmacro, keeps generating

(case un#   s 1   (m 60)   (h 3600) 

how can prevent outer parens?

just change map mapcat.

(defmacro defunits [quantity base-unit & units]   `(defmacro ~(symbol (str "unit-of-" quantity))      [valu# un#]      `(* ~valu#          ~(case un#             ~base-unit 1             ~@(mapcat (fn [x] ;; <----- mapcat instead of map change                         `(~(first x)                           ~(defunits-chaining                              (first x)                              (cons `(~base-unit 1)                                    (partition 2 units))                              nil)))                       (partition 2 units)))))) 

to elaborate, , respond currently-accepted answer: flatten never, never, never right (with rare exceptions use experts only). @ best it's band-aid right results simple inputs fail on complex inputs. instead, right use apply concat flatten list 1 level, or use mapcat instead of map generate already-flatter list, or perhaps more involved , specialized particularly convoluted data structure. here, simple mapcat needed.

i suppose should note defunits macro's inputs tightly constrained (they must symbols , numbers), in practice there no input flatten produce wrong output for. flatten bad habit into, , results in longer, more complicated code anyway.


Comments

Popular posts from this blog

linux - Does gcc have any options to add version info in ELF binary file? -

android - send complex objects as post php java -

charts - What graph/dashboard product is facebook using in Dashboard: PUE & WUE -