Probably the title is not 100% correct, but let me show you the issue:
(defmacro nvp!
[n width height]
`(q/defsketch (symbol (str (name '~n) "-viewport" ))
:title (name '~n))
In short: there's a macro called defsketch (it's part of the lib quil, but that does not matter). It's signature is basically defsketch [applet-name & options], and it creates something and binds it to a var called applet-name. For some reason, I want to wrap this into another macro that -- among other things -- takes an applet-name parameter, extends that name into applet-name-viewport and passes that to defsketch. I, however, am unable to figure out how to do that correctly (using macroexpand on the code above ((pprint (macroexpand(nvp test-name 500 500))), I get
(def(clojure.core/symbol (clojure.core/str (clojure.core/name 'my-namespace.core/test-name) "-viewport"))
(quil.applet/applet
:title (clojure.core/name 'my-namespace.core/test-name)))
(clojure.core/symbol (clojure.core/str (clojure.core/name 'my-namespace.core/test-name) "-viewport") -- this part looks good, but it should be evaluated somehow before passing it to the inner macro...
You need to unquote the form that generates the new symbol instead of the original symbol itself.
Here is a small example of how to accomplish this using a defn like macro for the inner macro:
(defmacro mydefn
[name & body]
`(defn ~name ~#body))
(defmacro defnview
[n & body]
`(mydefn ~(symbol (str (name n) "-viewport")) ~#body))
;; OR
(defmacro defnview
[n & body]
(let [n (symbol (str (name n) "-viewport"))]
`(mydefn ~n ~#body)))
Example:
(defnview foo [a] a)
;; => #'user/foo-viewport
(foo-viewport 1)
;; => 1
(macroexpand '(defnview foo [a] a))
;; => (def foo-viewport (clojure.core/fn ([a] a)))
Related
I'm learning common lisp. I have written a version of the once-only macro, which suffers from an unusual variable capture problem.
My macro is this:
(defmacro my-once-only (names &body body)
(let ((syms (mapcar #'(lambda (x) (gensym))
names)))
``(let (,,#(mapcar #'(lambda (sym name) ``(,',sym ,,name))
syms names))
,(let (,#(mapcar #'(lambda (name sym) `(,name ',sym))
names syms))
,#body))))
The canonical version of only-once is this:
(defmacro once-only ((&rest names) &body body)
(let ((gensyms (loop for n in names collect (gensym))))
`(let (,#(loop for g in gensyms collect `(,g (gensym))))
`(let (,,#(loop for g in gensyms for n in names collect ``(,,g ,,n)))
,(let (,#(loop for n in names for g in gensyms collect `(,n ,g)))
,#body)))))
The difference, as far as I can tell, is that the canonical version generates new symbols for every expansion of the macro using only-once. For example:
CL-USER> (macroexpand-1 '(once-only (foo) foo))
(LET ((#:G824 (GENSYM)))
`(LET (,`(,#:G824 ,FOO))
,(LET ((FOO #:G824))
FOO)))
T
CL-USER> (macroexpand-1 '(my-once-only (foo) foo))
`(LET (,`(,'#:G825 ,FOO))
,(LET ((FOO '#:G825))
FOO))
T
The variable my macro uses to store the value of foo is the same for every expansion of this form, in this case it would be #:G825. This is akin to defining a macro like the following:
(defmacro identity-except-for-bar (foo)
`(let ((bar 2))
,foo))
This macro captures bar, and this capture manifests when bar is passed to it, like so:
CL-USER> (let ((bar 1))
(identity-except-for-bar bar))
2
However, I cannot think of any way to pass #:G825 to a macro that uses my-only-once so that it breaks like this, because the symbols gensym returns are unique, and I cannot create a second copy of it outside of the macro. I assume that capturing it is unwanted, otherwise the canonical version wouldn't bother adding the additional layer of gensym. How could capturing a symbol like #:G826 be a problem? Please provide an example where this capture manifests.
We can demonstrate a behavioral difference between my-once-only and once-only:
Let's store our test form in a variable.
(defvar *form* '(lexalias a 0 (lexalias b (1+ a) (list a b))))
This test form exercises a macro called lexalias, which we will define in two ways. First with once-only:
(defmacro lexalias (var value &body body)
(once-only (value)
`(symbol-macrolet ((,var ,value))
,#body)))
(eval *form*) -> (0 1)
Then with my-once-only:
(defmacro lexalias (var value &body body)
(my-once-only (value)
`(symbol-macrolet ((,var ,value))
,#body)))
(eval *form*) -> (1 1)
Oops! The problem is that under my-once-only, both a and b end up being symbol-macrolet aliases for exactly the same gensym; the returned expression (list a b) ends up being something like (list #:g0025 #:g0025).
If you're writing a macro-writing helper that implements once-only evaluation, you have no idea how the symbol is going to be used by the code which calls the macro, whose author uses your once-only tool. There are two big unknowns: the nature of the macro and of its use.
As you can see, if you don't make fresh gensyms, it will not work correctly in all conceivable scenarios.
Most of my application state is stored in a large complex map. For the purposes of this question, I will use a simple structure:
(def data
{:a 1
:b {:c {:d 3}}})
I have a large number of functions which all follow the same pattern:
(defn update-map
[my-map val]
(let [a (:a my-map)
d (-> my-map :b :c :d)]
(assoc-in
(assoc my-map :a (+ a val))
[:b :c :d] (+ d val))))
I retrieve one or more values from the map, perform some calculations, and create a new map with updated values. There are two problems with this approach:
I have a lot of repetitive let bindings across different function definitions
If the schema of the map changes, I will have a lot of code to refactor
I've written a macro to reduce the boilerplate code required to define these functions. It works by looking up predefined getter and setter functions, and automatically generating a let block:
(def getters
{'a #(:a %)
'd #(-> % :b :c :d)})
(def setters
{'a #(assoc % :a %2)
'd #(assoc-in % [:b :c :d] %2)})
(defmacro def-map-fn
[name [& args] [& fields] & code]
(let [my-map 'my-map
lookup #(reduce % [] fields)
getter-funcs (lookup #(conj % %2 (list (getters %2) my-map)))
setter-funcs (lookup #(conj % (symbol (str "update-" %2)) (setters %2)))]
`(defn ~name [~my-map ~#args]
(let [~#getter-funcs ~#setter-funcs]
~#code))))
I can now define my functions more elegantly:
(def-map-fn update-map
[val] ; normal function parameters
[a d] ; fields from the map I will be using
(update-d
(update-a my-map (+ a val))
(+ d val)))
When expanded, it will produce a function definition looking something like this:
(defn update-map
[my-map val]
(let [a (#(:a %) my-map)
d (#(-> % :b :c :d) my-map)
update-a #(assoc % :a %2)
update-d #(assoc-in % [:b :c :d] %2)]
(update-d
(update-a my-map (+ a val))
(+ d val))))
One thing that is nagging me about my macro is that it is not intuitive to the programmer that the my-map function parameter is available for use within the function body.
Is this a good use of macros, or should I be using a different approach entirely (like dynamic var bindings)?
You could perhaps use lenses; the getters and setters then become composable functions. Have a look here or here.
Following the first link you can set up the lens as follows:
; We only need three fns that know the structure of a lens.
(defn lens [focus fmap] {:focus focus :fmap fmap})
(defn view [x {:keys [focus]}] (focus x))
(defn update [x {:keys [fmap]} f] (fmap f x))
; The identity lens.
(defn fapply [f x] (f x))
(def id (lens identity fapply))
; Setting can be easily defined in terms of update.
(defn put [x l value] (update x l (constantly value)))
(-> 3 (view id))
; 3
(-> 3 (update id inc))
; 4
(-> 3 (put id 7))
; 7
; in makes it easy to define lenses based on paths.
(defn in [path]
(lens
(fn [x] (get-in x path))
(fn [f x] (update-in x path f))))
(-> {:value 3} (view (in [:value])))
; 3
(-> {:value 3} (update (in [:value]) inc))
; {:value 4}
(-> {:value 3} (put (in [:value]) 7))
; {:value 7}
You can see form the above the the lens can be adapted to use get/set methods (such as get-in/update-in) based on the data structure you are working with. The real power of lenses which seems to also be what you are after is that you can compose them. In the same example the composition function can be defined as follows:
(defn combine [outer inner]
(lens
(fn [x] (-> x (view outer) (view inner)))
(fn [f x] (update x outer #(update % inner f)))))
(defn => [& lenses] (reduce combine lenses))
The => function can now be used to combine any arbitrary lenses such as:
(-> {:new {:value 3}} (view (=> (in [:new]) (in [:value]))))
; 3
(-> {:new {:value 3}} (update (=> (in [:new]) (in [:value])) inc))
; {:new {:value 4}}
(-> {:new {:value 3}} (put (=> (in [:new]) (in [:value])) 7))
; {:new {:value 7}}
The fact that (in [:new]) is just a function means that you could, for example, store it and manipulate it in various ways. For example, it would be possible to walk your nested map structure and create the lens functions which correspond to accessing the value at each level in the nested map and then at the end compose these functions together to create your getter/setter api. With this set up, your lenses could automatically adapt to any changes in your schema.
The ability to compose lenses can also make it easy to interact with the nodes of your nested map. For example, if you were to ever change the node from an atom to a list, you could simply add a new lens to work with it as follows:
(def each (lens seq map))
(-> {:values [3 4 5]} (view (=> (in [:values]) each)))
; (3 4 5)
(-> {:values [3 4 5]} (update (=> (in [:values]) each) inc))
; {:values (4 5 6)}
(-> {:values [3 4 5]} (put (=> (in [:values]) each) 7))
; {:values (7 7 7)}
I highly recommend looking at the full gist to see more examples of what you can do with lenses.
In this situation, my preference is to avoid the use of macros. They often obfuscate code, but more importantly they aren't composable. An ideal solution here would allow you to use the getter and setter functions outside of functions being defined in def-map-fn. I'd stick with regular functions and data as much as possible.
To begin with, you're concerned about having to rewrite a bunch of code if your schema changes. Fair enough. To address that, I'd start with a data representation of your map's schema. See Prismatic schema for a full-featured schema library for Clojure, but for now something along these lines should do:
(def my-schema
{:a :int
:b {:c {:d :int}}})
From this, you can compute the paths for all the properties in your schema:
(defn paths [m]
(mapcat (fn [[k v]]
(conj (if (map? v)
(map (partial apply vector k) (paths v)))
[k]))
m))
(def property-paths
(into {} (for [path (paths my-schema)] [(last path) path])))
Now, to get or set a property, you can look up its path and use that in conjunction with get-in, update-in, etc. as appropriate:
(let [d (get-in my-map (property-paths :d))]
;; Do something with d.
)
If you get tired of always calling get-in, assoc-in, etc., then you can pretty easily generate a bunch of getter functions:
(doseq [[p path] property-paths]
(eval `(defn ~(symbol (str "get-" (name p)))
[m#] (get-in m# ~path))))
(doseq [[p path] property-paths]
(eval `(defn ~(symbol (str "set-" (name p)))
[m# v#] (assoc-in m# ~path v#))))
(doseq [[p path] property-paths]
(eval `(defn ~(symbol (str "update-" (name p)))
[m# tail#] (apply update-in m# ~path #tail))))
Now you have your get-a, set-a, update-a functions available everywhere in your code, without having to call into some uber-macro to set up the bindings for you. For instance:
(let [a (get-a my-map)]
(-> my-map
(set-a 42)
(update-d + a)))
If you really find setting up the above let binding tedious, you could even write a with-properties macro that accepts a map and a list of property names and executes the body in a context that binds values for those names. But I probably wouldn't bother.
Advantages of this approach include:
It's schema-driven, so the schema is defined in one central place and used to generate other code as needed.
It prefers pure functions over macros, so code is more re-usable and composable.
It's an incremental approach that allows your application to grow more naturally. Rather than starting with an uber-macro that tries to anticipate all possible features you might want, you start with data and functions and sprinkle in macros to alleviate some of the repetitiveness as you see usage patterns emerge.
Why don't you just use update-in?
(defn update-map [my-map val]
(-> my-map
(update-in [:a] + val)
(update-in [:b :c :d] + val)))
I have the following Clojure code:
(defn mul [a b]
(* a b))
(defmacro create-my-macro [macroname]
`(defmacro ~macroname [a# b#]
(mul a# b#)))
(create-my-macro my-mul)
(my-mul 1 2)
;; => 2
(my-mul (+ 1 1) 2)
;; => ClassCastException clojure.lang.PersistentList cannot be cast to java.lang.Number
I get the answer I want when I wrap the arguments in the invocation of mul with eval:
(mul (eval #a) (eval #b))
But I don't understand why it is necessary to do that: if the my-mul macro had been defined directly (and not through another macro), it would work. For example, the following works fine:
(defmacro my-mul [a b] `(mul ~a ~b))
(my-mul (+ 1 1) 2)
;; => 4
Why am I seeing this behavior?
Edit: In response to a comment, below are the macroexpands for the failing case (i.e., without using eval):
(macroexpand '(create-my-macro my-mul))
;; => (do
;; (clojure.core/defn my-mul
;; ([&form &env a__58__auto__ b__59__auto__]
;; (foo/mul a__58__auto__ b__59__auto__)))
;; (. (var my-mul) (setMacro)) (var my-mul))
(macroexpand '(my-mul (+ 1 1) 2))
;; => ClassCastException clojure.lang.PersistentList cannot be cast to java.lang.Number clojure.lang.Numbers.multiply (Numbers.java:146)
As you show, the code you'd like to emit looks like:
(defmacro my-mul [a b] `(mul ~a ~b))
So you need to syntax-quote it and suffix all locals with #:
`(defmacro my-mul [a# b#] `(mul ~a# ~b#))
Thus you macro-emitting macros should be:
(defmacro create-my-macro [macroname]
`(defmacro ~macroname [a# b#]
`(mul ~a# ~b#)))
(defmacro create-my-macro [macroname]
`(defmacro ~macroname [a# b#]
`(mul ~a# ~b#)))
I have a record (defrecord Rec [id])
I work with it like
(def my ( Rec. 2 ))
(println (:id my))
Now I want to replace record def with macro. So that I could write just
(r 2)
(println (:id my))
I wrote macro
(defmacro r [id]
(list 'def 'my (symbol "(") 'Rec. id (symbol ")")))
I checked it with macroexpand
(macroexpand-1 '(r 2)) => (def my ( Rec. 2 ))
But I get RuntimeException: Too many arguments to def on (r 2).
Creating a symbol out of a left paren is not the same as eval-ing text with a left paren. No special significance is attached to the former; the latter causes the reader to produce a nested list which is then evaluated.
In other words, Clojure evaluates data structures, not text (or a list of symbols). When you type something in the REPL, that text is read into a data structure, then the data structure is evaluated.
For this to work correctly, the macro needs to produce a nested list itself:
(defmacro r [id]
(list 'def 'my (list 'Rec. id)))
Or better yet, use the syntax quote operator:
(defmacro r [id]
`(def my (Rec. ~id)))
For illustrative purposes, you can see what happens when Clojure code is read as text:
(read-string "(def my (Rec. 2))")
=> (def my (Rec. 2))
(map type (read-string "(def my (Rec. 2))"))
=> (clojure.lang.Symbol clojure.lang.Symbol clojure.lang.PersistentList)
I'm working on some java library wrapper.
We have some object with methods and can invoke them with (.method object ...). I want to create more convenient api with number of functions (method object ...).
I wrote a simple macro:
(defmacro ^{:private true} gen-method [method & argv]
`(def ~method (memfn ~method ~#argv)))
Now I can invoke (gen-method charAt i) for example and after that I can use (charAt "string" 1).
But I have a lot of method to generate and want to use something like:
(map #(gen-method (-> %1 name symbol arg)) [:charAt :substring ...])
But this is not working. Next example is not working too:
(map #(let [fname (-> %1 name symbol)] (gen-method fname arg)) [:charAt :substring ...])
What I need to change in macro or add something for correct behaviour ?
Thanks.
You will have to take the map operation inside the macro itself as the map operation should happen at compile time i.e form expanding time and not at runtime.
Something like below:
(defmacro ^{:private true} gen-methods [methods]
`(do
~#(map (fn [[x & i]] (let [m (-> x name symbol)] `(def ~m (memfn ~m ~#i)) )) methods)))
(gen-methods [ [:charAt i] [:substring i]])