I try to write a macro, which given a name could be supplied in the function myfunc to create a class and make an instance of this class.
Here is the code:
(defmacro define-class (class-name)
`(eval
`(progn
(defclass ,,class-name () ())
(make-instance ,class-name))))
(defun myfunc (name)
(define-class name))
I can compile successfully the macro but not the function. In this case I get a warning at compilation time saying that:
undefined variable: CLASS-NAME
If I modify a bit the macro so that instead of writing
(make-instance ,class-name)
I write
(make-instance ,,class-name)
Then in this case I can compile both, but when running (myfunc 'toto) I get the following error:
The variable TOTO is unbound.
I try to figure out how the macro is expanded with macroexpand-1. With the first macro which is defined with (make-instance ,class-name) it gave me the following result:
(EVAL `(PROGN (DEFCLASS ,'TOTO NIL NIL) (MAKE-INSTANCE ,CLASS-NAME)))
Whereas in the second macro which is defined with *(make-instance ,,class-name) it gave me the following result:
(EVAL `(PROGN (DEFCLASS ,'TOTO NIL NIL) (MAKE-INSTANCE ,'TOTO)))
But I guess the right expansion in my case would be something like:
(EVAL `(PROGN (DEFCLASS ,'TOTO NIL NIL) (MAKE-INSTANCE 'TOTO)))
How could I modify or re-write the macro so that it works?
You want to write code like this:
(defun myfunc (name)
(define-class name))
This would actually be similar to this:
(defun myfunc (name)
(let ((name name))
(eval `(defclass ,name () ()))
(make-instance name)))
Thus the DEFINE-CLASS macro should generate something like above code.
(defmacro define-class (name)
(let ((name-sym (gensym "CLASS-NAME")))
`(let ((,name-sym ,name))
(eval `(defclass ,,name-sym () ()))
(make-instance ,name-sym))))
Using it:
CL-USER 21 > (pprint (macroexpand-1 '(define-class name)))
(LET ((#:CLASS-NAME22897 NAME))
(EVAL `(DEFCLASS ,#:CLASS-NAME22897 NIL NIL))
(MAKE-INSTANCE #:CLASS-NAME22897))
CL-USER 22 > (myfunc 'baz42)
#<BAZ42 40202BBE73>
But then, there is no reason that it should be a macro!
A normal function is just fine...
(defun create-class-and-instance (name)
(eval `(defclass ,name () ()))
(make-instance name))
The defclass macro generally expands into a call to the actual implementation-dependent function that creates the class. If you can call that function instead, you can get rid of eval. This is a little more direct and keeps the current lexical environment.
If you load the closer-mop system, you can write your function as follows:
(defun make-instance-from-new-class (class-name)
(make-instance (closer-mop:ensure-class class-name)))
Related
I am trying to do the following: separate a function that gets values from some user input from the function that uses it.
I have tried the following code for the proof of concept initially (that worked):
(defun initialiser (bindings)
(cl-loop for (var) in bindings do
(set var (read-from-minibuffer "Input value: "))))
That i have tested with:
(let ((name))
(initialiser '((name)))
(message "name is %S" name))
The idea was to pass bindings to the function that handles input in the form like ((name "Name") (address "Post address") (code "County code")) or something similar, and in there assign the input.
After testing above i have come up with the following macro to do things:
(defmacro initialise-and-execute (bindings initialiser &rest callback-actions)
(let ((unwrapped-bindings (map 'list (lambda (binding) (car binding)) bindings)))
`(let ,unwrapped-bindings
(,initialiser (quote ,bindings)
(lambda () ,#callback-actions)))))
However, in the "real" scenario the assignments must happen in callbacks, like:
(defun initialiser(bindings)
(cl-loop for (var) in bindings collect
(lambda () (set var (read-from-minibuffer "Input value: ")))
into callbacks
return callbacks))
This fails to work. Code i have used to test was:
(defvar callbacks nil)
(let ((name))
(setq callbacks (initialiser '((name)))))
(funcall (car callbacks))
Edit: changed the code the following way:
(defmacro initialise-and-execute (bindings initialiser &rest callback-actions)
(let ((unwrapped-bindings (map 'list (lambda (binding) (car binding)) bindings)))
`(lexical-let ,unwrapped-bindings
(,initialiser
(quote ,(map 'list
(lambda (binding) (list (cadr binding)
`(lambda (val) (setq ,(car binding) val))))
bindings))
(lambda () ,#callback-actions)))))
What it must do: generate number of lambdas that share the same lexical environment - one that uses captured variables and the rest that modify them.
However, what i get is, regrettably, something else. Symbols used in callback-actions do not resolve into the values set.
For completeness, here is how i tested it:
(defun init-values (bindings callback)
(loop for (desc setter) in bindings
for idx = 0 then (incf idx)
do (print (format "Setting %s" desc))
(funcall setter idx))
(funcall callback))
(initialise-and-execute
((name "Name")
(surname "Surname"))
init-values
(message "name is %S" name))
Here, lambdas were not generated in a loop and values in the context of a lexical binding were assigned with setq.
To set the function value, use fset, not set.
(defun initialiser(bindings)
(cl-loop for (var) in bindings collect
(lambda () (fset var (read-from-minibuffer "Input value: ")))
into callbacks
return callbacks))
There are possible issues:
in a LOOP the VAR is possibly assigned on each iteration, not bound (that's in Common Lisp). so your callbacks set all the same VAR value.
in a lexical bound Lisp (new in GNU Emacs Lisp) one can't set the variable values with SET
Examples:
ELISP> (mapcar #'funcall
(cl-loop for i in '(1 2 3 4)
collect (lambda () i)))
(4 4 4 4)
all closures have the same value of i
ELISP> (let ((a 'foobar))
(set 'a 42)
a)
foobar
SET had no effect on the local variable
In Common Lisp I might write something like:
(defun initializer (bindings)
(loop for (what setter) in bindings
for new-value = (progn
(format t "Enter ~a: " what)
(finish-output)
(read-line))
do (funcall setter new-value)))
(defmacro call-with-bindings (name-sym-list fn)
(let ((value-sym (gensym "v")))
`(,fn
(list ,#(loop for (name sym) in name-sym-list
collect `(list ,name ,`(lambda (,value-sym)
(setf ,sym ,value-sym))))))))
CL-USER > (let (name age)
(call-with-bindings (("name" name) ("age" age))
initializer)
(format t "name is ~S~%" name)
(values name age))
Enter name: Lara
Enter age: 42
name is "Lara"
"Lara"
"42"
Where we can look at the macro expansion:
CL-USER > (pprint (macroexpand-1
'(call-with-bindings (("name" name) ("age" age))
initializer)))
(INITIALIZER (LIST (LIST "name"
(LAMBDA (#:|v1669|)
(SETF NAME #:|v1669|)))
(LIST "age"
(LAMBDA (#:|v1669|)
(SETF AGE #:|v1669|)))))
After some experimenting, i have been able to do it. The key was realising that lexical-let apparently had some restrictions on how the lambda should be placed for them to have the same closure context. After i have managed to generate set of closures that referred to the same variables, the rest was easy.
Here is the final code:
(defmacro make-lamba-set (bindings &rest callback-actions)
"Make set of closures with shared context
BINDINGS are a list of form (SYMBOL NAME), where SYMBOL is not defined yet
CALLBACK-ACTIONS are forms that use symbols from bindings
Return created captures a as a list of forms:
(do-callback-actions (set-symbol NAME) ...)"
(let ((unwrapped-bindings (map 'list
(lambda (binding)
(car binding))
bindings)))
`(lexical-let ,unwrapped-bindings
(list (lambda () ,#callback-actions)
,#(map 'list
(lambda (binding)
`(list
(lambda (val)
(setq ,(car binding) val))
,(cadr binding)))
bindings)))))
(defmacro initialise-and-execute (bindings initialiser &rest callback-actions)
"BINGINGS have form of ((BINDING-SYMBOL PROMPT) ...)
INITIALISER somehow assigns values to all of BINDING-SYMBOL
then it calls CALLBACK-ACTIONS with values of BINDING-SYMBOL set"
`(let ((closure-parts (make-lamba-set ,bindings ,#callback-actions)))
(,initialiser (cdr closure-parts)
(car closure-parts))))
Here is how i tested it:
(defun init-values (bindings callback)
(loop for (setter desc) in bindings
for idx = 0 then (incf idx)
do (message "Setting %s" desc)
(funcall setter idx))
(funcall callback))
(initialise-and-execute ((name "Name")
(surname "Surname"))
init-values
(insert (format "Name is %S and surname is %S"
name
surname)))
That gave me expected output of:
Name is 0 and surname is 1
I'm trying to create a macro (bar) that should be used like this:
(let ((my-var "foo"))
(bar ("some")
:buzz (lambda () (format t "~a~%" my-var))))
The macro should basically just FUNCALL the lambda with taking MY-VAR into account.
What I've come up with is this:
(defmacro bar ((thing) &body body)
`(funcall (coerce (getf (list ,#body) :buzz) 'function)))
This works, it prints "foo".
But I'd like to know if this is how this is done or if there is a better way of doing this.
Well, for a start if you don't need the extra, unused argument, then this is just funcall, since (lambda ...) denotes a function.
(let ((my-var "foo"))
(funcall (lambda () (format t "~a~%" my-var))))
So even if you didn't want to call this funcall you could write it as a function, not a macro: it's not doing any code transformation. But presumably you actually do need this extra argument, and you are intending to use it for some purpose in the expansion, so what you need then is a macro which takes keyword arguments and just expands into a suitable funcall form:
(defmacro bar ((thing) &key (buzz '(lambda ())))
(declare (ignore thing))
`(funcall ,buzz))
I am trying the following code to write a macro that, given a name of a class, automatically creates a class with a name instance variable and an accessor for it in the form of classname-name.
(defmacro def-named-class (class-name)
`(defclass ,class-name ()
((name :accessor ,(intern (format nil "~A-~A" class-name "name"))
:initarg :name
:initform ""))))
The problem here is that, when the macro runs, say with an argument foo, the name of the accessor function comes as |FOO-name|, but I would want it to be just foo-name. The reason is, (intern "foo-name") returns a symbol |foo-name|. However, if I try to do the same with a normal function, like this:
(defmacro def-hyp (name1 name2 arg-list &body body)
`(defun ,(intern (format nil "~A-~A" name1 name2))
,arg-list
,#body))
And then call it like (def-hyp foo name () 'foo-name) it correctly produces a function with name foo-name. So I'm wondering if there's any method to get the exact same symbol from the string representation inside the first macro. I am using Clozure CL.
Note that a class already has a name.
CL-USER 19 > (defclass foo () ())
#<STANDARD-CLASS FOO 415040BE6B>
CL-USER 20 > (class-name *)
FOO
Isn't it better solved by inheritance? Here is your mixin:
(defclass named ()
((name :initarg :name :accessor name-of)))
... and you can use it for all other classes that define objects which have a name:
(defclass this (named) ...)
(defclass that (named) ...)
You should convert the name to upper case:
(defmacro def-named-class (class-name)
`(defclass ,class-name ()
((name :accessor ,(intern (format nil "~A-~A" (string-upcase class-name) "NAME"))
:initarg :name
:initform ""))))
Another possibility, as suggested in a comment by jkiiski, is to change only the format string:
...
((name :accessor ,(intern (format nil "~:#(~A-~A~)" class-name "name"))
...
The reason is that the default behaviour of the Common Lisp reader is to transform any symbol in upper-case on reading it. So, when you write foo-name, it is automatically transformed into FOO-NAME. To obtain it, you should use (intern "FOO-NAME"). However, if you want, you can change the default behaviour of the reader (see the manual).
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'm writing a small special-purpose language in Common Lisp using a defmacro. I cannot figure out the proper backquote procedure to have a variable defined in a top-level let statement, shadowed in a nested macrolet, and returned in a nested labels, all point to the same symbol.
Here's some small example code that shows the problem:
(defmacro with-keylang (&body body)
(let ((keyblank-size-x (gensym)))
`(let ((,keyblank-size-x 42))
(labels ((keyblank-size-x ()
,keyblank-size-x))
(macrolet ((with-keyblank-size-x (size-x &body body)
`(let ((,',keyblank-size-x ,size-x))
,#body)))
,#body)))))
CL-USER>
(with-keylang
(print (keyblank-size-x)))
42
42
All is well so far.
CL-USER>
(with-keylang
(with-keyblank-size-x 24
(print (keyblank-size-x))))
;Compiler warnings :
; In an anonymous lambda form: Unused lexical variable #:G123171
42
42
There's the problem. I want the symbol representing keyblank-size-x to be shadowed with the value 24, and this is not happening.
I have a feeling that the ,', backquote pattern isn't proper for this case, as this quotes the symbol representing keyblank-size-x, and is therefore not eq. But if I try ,,, it doesn't work, and I get this interesting compiler error:
While compiling WITH-KEYBLANK-SIZE-X :
Illegal reference to lexically defined variable #:G123192.
[Condition of type CCL::COMPILE-TIME-PROGRAM-ERROR]
EDIT:
The keyblank-size-x variable was lexically scoped, and I wanted dynamic scope for this particular case. So here's the rewrite declaring the keyblank-size-x variable to have dynamic scope:
(defmacro with-keylang (&body body)
(let ((keyblank-size-x (gensym)))
`(let ((,keyblank-size-x 42))
(declare (special ,keyblank-size-x))
(labels ((keyblank-size-x ()
,keyblank-size-x))
(macrolet ((with-keyblank-size-x (size-x &body body)
`(let ((,',keyblank-size-x ,size-x))
(declare (special ,',keyblank-size-x))
,#body)))
,#body)))))
And the test code:
CL-USER>
(with-keylang
(with-keyblank-size-x 25
(with-keyblank-size-x 21
(print (keyblank-size-x)))
(print (keyblank-size-x)))
(print (keyblank-size-x)))
21
25
42
42
If we fully expand the code (here using the Walk command in LispWorks):
(LET ((#:G19508 42))
(LABELS ((KEYBLANK-SIZE-X () #:G19508))
(MACROLET ((WITH-KEYBLANK-SIZE-X (SIZE-X &BODY BODY)
`(LET ((#:G19508 ,SIZE-X))
,#BODY)))
(LET ((#:G19508 24))
(PRINT (KEYBLANK-SIZE-X))))))
Rebinding #:G19508 has no effect and can't have. The function keyblank-size-x has a different lexical binding. This is just the usual effect of lexical binding.