I want to construct a macro that, given a symbol 'foo, creates a method called foo*. How can I concatenate 'foo and '*?
(let [s (symbol 'test)]
(symbol (str s "*")))
(symbol (str 'foo "*"))
Related
Here's my macro, what it is supposed to do is to wrap a body in let with bindings from vars-alist
(defmacro with-vars-alist (vars-alist &rest body)
`(let (,#(mapcar (lambda (cell) (list (car cell) (cdr cell))) vars-alist))
,#body))
When I am looking at what it expands to using following code
(defvar my-vars-alist '((var1 . "var1")
(var2 . "var2")))
(macroexpand-1 (with-vars-alist my-vars-alist `(concat ,var1 ,var2)))
I get an error cons: Wrong type argument: sequencep, my-vars-alist
However checking it (sequencep my-vars-alist) return t.
The error is probably has some simple solution, but I am just unable to find it.
Remember that arguments to macros are un-evaluated, which means that when you pass my-vars-alist as an argument, it is passed verbatim as the symbol my-vars-alist.
Therefore during the macro expansion, vars-alist evaluates to the symbol my-vars-alist rather than the list ((var1 . "var1") (var2 . "var2")).
So the error isn't complaining that the variable my-vars-alist doesn't contain a sequence as its value, but rather that the symbol my-vars-alist is not itself a sequence (which is correct -- it's a symbol).
checking it (sequencep my-vars-alist) return t.
Which is also correct, as there my-vars-alist is evaluated as a variable to its value of ((var1 . "var1") (var2 . "var2"))
So you need to eval that argument. e.g.:
,#(mapcar (lambda (cell) (list (car cell) (cdr cell)))
(eval vars-alist))
As vars-alist is already being evaluated to the symbol my-vars-alist, this change means that we are passing that symbol my-vars-alist to eval, which evaluates it as a variable to obtain the list needed for mapcar.
You probably also wanted to quote the form you pass to macroexpand-1 (or use M-x pp-macroexpand-last-sexp).
I looks like what you're trying to do is let-bind the keys of an alist to their values, so you can use the keys as variables in the let body. There's a built in macro for this in recent Emacs:
(let-alist '((a . 1) (b . 2))
(message "a: %d, b: %d" .a .b))
(defmacro foo (x)
`(defun ,xt ()
(format t "hullo")))
(foo bar)
will not define a function bart, since ,xt is read as the variable xt rather than the variable x plus a t. But is there a way to get a function bart by supplying the argument bar?
You need to create the function name (which is a string then) and then convert it to a symbol, for example:
(defmacro foo (x)
`(defun ,(intern (format nil "~aT" x)) ()
(format t "hullo")))
then
? (foo bar)
BART
? (bart)
hullo
NIL
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)))
I would like to initiate dynamically a hash table with defmethod or defun using one of the arguments to create the name. For instance:
(defun foo (arg)
(let ((NAME (read-from-string (format nil "\*~S\*" arg))))
(defparameter NAME (make-hash-table))))
Of course, foo create hash table with the symbol NAME, instead of the value of NAME in let. What can I do to get the value of NAME to create this hash table?
General Remarks
It is almost always wrong to create global variables in functions.
It is also almost always wrong to create new symbols using read-from-string instead of intern.
Use a Macro
What you probably want is
(defmacro def-ht (name)
(let ((var (intern (concatenate 'string "*" (symbol-name name) "*")
(symbol-package name))))
`(defparameter ,var (make-hash-table))))
(def-ht foo)
Use a Function
You might be able to do it in a function too - by inspecting the macroexpansion of a defparameter form and placing the needed stuff in the function:
(defun make-ht-var (name)
(let ((var (intern (concatenate 'string "*" (symbol-name name) "*")
(symbol-package name))))
(setf (symbol-value var) (make-hash-table))
(proclaim (list var 'special))))
(make-ht-var 'foo)
Note that the argument to the function is quoted, but the argument to the macro is not.
You need to use a macro instead of a function. DEFPARAMETER will bind value of MAKE-HASH-TABLE to the symbol NAME because it evaluates at macro-expansion time which occurs earlier than run-time, which is when the function FOO binds the lexical value of NAME.
Look up the CL evaluation model for a deeper understanding.
(defmacro foo (arg)
(let ((name (read-from-string (format nil "*~S*" arg))))
`(defparameter ,name (make-hash-table))))
(foo "my-hash")
=> <hash-table 0x121>
*my-hash*
=> <hash-table 0x121>
I want to write some special reader macros:
[hello "world"] ; <=> (funcall #'|hello| "world")
{hello "my" ("world")} ; <=> (apply #'|hello| "my" ("world"))
Can this be implemented? And how would you do it?
Yes, the term you are wanting is readtable (Common Lisp HyperSpec chapter 23 and Common Lisp HyperSpec chapter 2 talk about the relevant concepts).
You'll need to first define a function that can read the data you are interested in, then return it in the form you want it.
(defun read-case-preserve-funcall-or-apply (stream char)
(let ((preserved-readtable-case (readtable-case *readtable*)))
(setf (readtable-case *readtable* :preserve))
(let ((tmp (read-delimited-list (if (char= char #\[) #\] #\}) stream t)))
(let ((fun (car tmp))
(args (cdr tmp)))
(cond ((char= char #\[) `(funcall (function ,fun) ,#args))
((char= char #\{) `(apply (function ,fun) ,#args)))))))
After that, you need to hook it up to the readtable and copy some syntax-markers from ( and ) to your new delimiters.