I have defined the following simple macro:
(defmacro define-class (class-name)
`(defclass ,class-name ()()))
And now I want to use it in the following function:
(defun create-data (mode)
(define-class mode))
After compiling the last function I get the following message, the variable MODE is defined but never used.
And when I execute the function to create a class "myclass", I get instead the creation of a class of type "mode":
(create-data 'myclass)
#<STANDARD-CLASS MODE>
Seems that my argument is not used? How can I get the function create-data to use the argument?
defclass isn't a function but a macro. It uses the name provided in the source (mode in your case) and it's not the same as your variable mode. In fact some CL implementations would warn you that argument mode is never used.
You can macroexpand it (macroexpand '(defclass mode ()())) to check what it becomes in your implementation. I get this in CLISP (I've cleaned it up a little):
(progn
(eval-when (compile load eval)
(apply #'ensure-class
'mode ; notice mode is quoted
:direct-superclasses (list)
:direct-slots (list)
:metaclass clos::<standard-class>
(append '(:fixed-slot-locations nil)
(list :direct-default-initargs nil
:documentation nil
:generic-accessors 't))))
(find-class 'mode)) ; notice mode is quoted
The expansion is imlementation dependent but the result is the same in all. mode is the name of the class being defined and not what you pass as argument.
You should use (define-class myclass) instead of (create-data 'myclass).
I would use something like this:
CL-USER 86 > (defmacro define-class (class-name)
`(defclass ,class-name ()()))
DEFINE-CLASS
CL-USER 87 > (defun create-data (mode)
(funcall (compile nil `(lambda ()
(define-class ,mode)))))
CREATE-DATA
CL-USER 88 > (create-data 'bar)
#<STANDARD-CLASS BAR 402016CC73>
Above uses code generation and the built-in compiler.
Related
I would like to try extending some Lisp (Scheme, Racket, Clojure, any) to run external commands as follows:
; having
(define foo ...)
(define bar ...)
; on command
(ls (foo bar) baz)
; this lisp should evaluate (foo bar) as usual, with result "foobar", then
(ls foobar baz)
; here "ls" is not defined
; instead of rising "undefined identifier" exception
; it must look for "ls" command in the directories
; in the "PATH" environment variable
; and launch the first found "ls" command
; with strings "foobar" and "baz" on input
I just want to run it anyhow, without carrying about correct conversion from lisp's data structures to strings or handling the exit code and the output of the command in stdout/stderr.
I think there is no way to extend it within normal environment (like catching the "undefined" exception all the time). The eval procedure of the interpreter itself must be changed.
Which Lisp is the best to extend it like this and how is it done? Maybe there already exists a project performing something similar?
Common Lisp has a standard error system which may be used to implement that.
In Common Lisp implementations which provide a use-value or store-value restart for errors of type undefined-function.
Example
CL-USER 69 > (flet ((call-use-value-restart (c)
(use-value (lambda (arg)
(format t "~%dummy function with arg ~a~%" arg))
c)))
(handler-bind ((undefined-function #'call-use-value-restart))
(this-function-does-not-exist "foo")))
dummy function with arg foo
NIL
In the above example the function this-function-does-not-exist does not exist. As you can see, the error is handled and another function is called instead, which then does some output.
If we call the undefined function on its own, we get an error:
CL-USER 70 > (this-function-does-not-exist "foo")
Error: Undefined operator THIS-FUNCTION-DOES-NOT-EXIST in form (THIS-FUNCTION-DOES-NOT-EXIST "foo").
1 (continue) Try invoking THIS-FUNCTION-DOES-NOT-EXIST again.
2 Return some values from the form (THIS-FUNCTION-DOES-NOT-EXIST "foo").
3 Try invoking something other than THIS-FUNCTION-DOES-NOT-EXIST with the same arguments.
4 Set the symbol-function of THIS-FUNCTION-DOES-NOT-EXIST to another function.
5 Set the macro-function of THIS-FUNCTION-DOES-NOT-EXIST to another function.
6 (abort) Return to top loop level 0.
Type :b for backtrace or :c <option number> to proceed.
Type :bug-form "<subject>" for a bug report template or :? for other options.
CL-USER 71 : 1 >
Our example basically calls the restart number 3 programmatically:
It binds a handler which calls the function call-use-value-restart when an error of type undefined-function happens.
The function call-use-value-restart then calls the use-value restart with a function it provides. Here you could provide a function which calls an external program of the name given by (cell-error-name c). The use-value restart then just calls the provided function and keeps on executing the program as usual.
Hint for a solution
Typically one would write a small top-level loop where such a handler is provided.
Another way to call the restart
In this example we use a hook to add a handler in case an error happens. Here we use the global variable *debugger-hook*. This should be a function and in our case it calls a new function when the condition c is of type undefined-function.
* (defun provide-a-function-hook (c hook)
(declare (ignore hook))
(typecase c
(undefined-function (use-value (lambda (arg)
(format t "~%dummy function with arg ~a~%" arg))
c))))
PROVIDE-A-FUNCTION-HOOK
* (setf *debugger-hook* #'provide-a-function-hook)
#<FUNCTION PROVIDE-A-FUNCTION-HOOK>
* (this-function-does-not-exist "foo")
; in: THIS-FUNCTION-DOES-NOT-EXIST "foo"
; (THIS-FUNCTION-DOES-NOT-EXIST "foo")
;
; caught STYLE-WARNING:
; undefined function: THIS-FUNCTION-DOES-NOT-EXIST
;
; compilation unit finished
; Undefined function:
; THIS-FUNCTION-DOES-NOT-EXIST
; caught 1 STYLE-WARNING condition
dummy function with arg foo
NIL
In racket you may override #%top:
#lang racket
(provide
(combine-out
(except-out (all-from-out racket) #%top)
(rename-out [shell-curry #%top])))
(require racket/system)
(define (stringify a)
(~a (if (cmd? a) (cmd-name a) a)))
(struct cmd (name proc)
#:property prop:procedure
(struct-field-index proc)
#:transparent
#:methods gen:custom-write
[(define (write-proc x port mode)
(display (string-append "#<cmd:" (stringify x) ">") port))])
(define (shell name)
(define (cmd-proxy . args)
(define cmd
(string-join (map stringify (cons name args))
" "))
(system cmd))
cmd-proxy)
(define-syntax shell-curry
(syntax-rules ()
((_ . id)
(cmd 'id (shell 'id)))))
Save this as shell.rkt and make this runner.rkt in the same directory:
#lang s-exp "shell.rkt"
(define test (list /bin/ls /usr/bin/file))
(second test) ; ==> #<cmd:/usr/bin/file>
(first test) ; ==> #<cmd:/bin/ls>
((second test) (first test))
; ==> t (prints that /bin/ls is an executable on my system)
Now from here to make it a #lang myshell or something like that is pretty easy.
To me these operators seem to do the same thing. Both take a symbol and return the function associated with it. Is there any difference?
elisp evaluation returns the following:
(defun foo (x) (+ 1 x))
foo
(foo 3)
4
#'foo
Which I don't understand either.
Furthermore is there a difference between common lisp and elisp? I'm learning from resources on either.
Common Lisp:
SYMBOL-FUNCTION can't retrieve functions from lexically bound functions. FUNCTION references the lexically bound function by default. #'foo is just a shorter notation for (FUNCTION foo).
CL-USER 1 > (defun foo () 'foo)
FOO
CL-USER 2 > (flet ((foo () 'bar))
(list (funcall (symbol-function 'foo))
(funcall #'foo)
(funcall (function foo))
(eq (function foo) (symbol-function 'foo))))
(FOO BAR BAR NIL)
CL-USER 3 > (eq (function foo) (symbol-function 'foo))
T
Rainer's answer discusses the things that you can do with function that you can't do with symbol-function, namely retrieve the value of lexically scoped functions, but there are a few other differences too.
The special operator FUNCTION
The special operator FUNCTION provides a way to find the functional value of a name in a lexical environment. Its argument is either a function name or a lambda expression. That function can take a lambda expression means that you can write: (function (lambda (x) (list x x))). The term function name includes more than just symbols. It also includes lists of the form (setf name), which means that you can do things like (function (setf car)).
The accessor SYMBOL-FUNCTION
The accessor symbol-function, on the other hand, lets you retrieve and set the functional value of a symbol. Since it requires a symbol, you can't do (symbol-function (lambda …)) or (function (setf name)). Symbol-function also can't see lexical environments; it only works with global definitions. E.g.,
(flet ((foo () 'result))
(symbol-function 'foo))
;=> NIL
Since symbol-function is an accessor, you can change the value of a function's symbol with it. E.g.:
CL-USER> (setf (symbol-function 'foo) (lambda () 42))
#<FUNCTION (LAMBDA ()) {1005D29AAB}>
CL-USER> (foo)
42
CL-USER> (setf (symbol-function 'foo) (lambda () 26))
#<FUNCTION (LAMBDA ()) {1005D75B9B}>
CL-USER> (foo)
26
The accessor FDEFINITION
There's also the accessor fdefinition which is kind of like symbol-function in that is can only access globally defined functions, but kind of like function in that it can access of symbols and (setf name) lists. However, it does not retrieve the value of lambda functions.
Based on the example provide in the practical common lisp reference, I define a macro to create a class as followed.
(defmacro define-class (class-name class-slot)
`(defclass ,class-name ()
,(mapcar #'slot->defclass-slot class-slot))))
The function slot->declass-slot take a single argument and generate a standard line describing a slot in a class. The code is the following:
(defun slot->defclass-slot (spec)
`(,spec :initarg ,(as-keyword spec) :accessor ,spec :initform 0))
For example,
(slot->defclass-slot 'nom)
(NOM :INITARG :NOM :ACCESSOR NOM :INITFORM 0)
All this work fine, when I create a class 'model' as follow:
(define-class model (nom id))
But suppose that I define a parameter instead.
(defparameter *test* '(nom id))
(define-class model *test*)
Then, the code end-up in an error:
The value *TEST* is not of type LIST.
What is wrong?
Your define-class macro does not evaluate its class-slots argument.
You can "fix" your code like this:
(defmacro define-class (class-name class-slots)
`(eval
`(defclass ,',class-name ()
,#(mapcar #'slot->defclass-slot ,class-slots))))
(macroexpand-1 '(define-class model '(nom id)))
(defparameter *test* '(nom id))
(define-class model *test*)
Note that you now have to quote the literal second argument to define-class.
Note also that you are now using eval (for a good reason, in this case).
Note finally that I seriously doubt that you truly want to do this. Chances are you don't need this level of dynamism, and you are just complicating your life for no good reason.
E.g., if you just want to get the list of class slots (using your *test* variable), you should use MOP instead.
In fact you can make your macro expand to the function ensure-class:
> (mop:ensure-class 'foo :direct-slots '((:name a)))
#<STANDARD-CLASS FOO>
but this relies on a somewhat brazen assumption that your implementation is MOP-compliant.
(defparameter *test* '(nom id))
(define-class model *test*)
You shouldn't try to do this, for the same reason that you never try to do:
(with-open-file '(...)
...)
The point of the macro is to not evaluate the arguments in order that you can do something with them. What you can do instead, if you do for some reason, need both a macro- version and non-macro- version, is to define the macro functionality in terms of a function, and then wrap the function in a macro when you need a macro. E.g., (for a not-particularly robust) with-open-file):
(defun %with-open-file (filename function &rest args)
(let ((file (apply 'open filename args)))
(prog1 (funcall function file)
(close file))))
(defmacro with-open-file ((var filename &rest args) &body body)
`(%with-open-file ,filename
(lambda (,var) ,#body)
,#args))
Then you can use the macro-version when you want it, and the function-version when you want it. In your case, though, that's not a perfect solution, since you're expanding to another macro call.
I store some macros in quoted form (because in fact they produce lambdas with tricky lexical environment and I prefer store and serialize them as lists). So now I'm trying:
(defun play (s)
(funcall (macroexpand s)))
Macroexpand evaluates quoted lambda, so funcall can't run it. How to unquote result of macroexpand without eval? Because in my case it would cause indefensible security hole.
MORE INFO:
What I get look like this (in simplest case):
FUNCALL: #1=#'(LAMBDA (#:G6008) (SYMBOL-MACROLET NIL T)) is not a function name; try using a symbol instead
and symbol-macrolet is what actually builds up "tricky lexical environment" inside lambda.
Macroexpand evaluates quoted lambda, so funcall can't run it. How to
unquote result of macroexpand without eval? Because in my case it
would cause indefensible security hole.
I think that Sylwester's comment about the XY problem is probably right here; it sounds like you're trying to do something that might be done better in a different way. That said, if you have a list that's a lambda expression, you can use coerce to get a function object instead of using eval. That is, you can do this:
CL-USER> (funcall '(lambda () 42))
; Error, like you've been having
CL-USER> (funcall (coerce '(lambda () 42) 'function))
42 ; turned the list (lambda () 42) into a function and called it
This is described in the documentation for coerce; when the "output" type is function, this is what happens with the object argument:
If the result-type is function, and object is any function name that
is fbound but that is globally defined neither as a macro name nor as
a special operator, then the result is the functional value of object.
If the result-type is function, and object is a lambda expression,
then the result is a closure of object in the null lexical
environment.
Thus, if you have a function that returns list of the form (lambda ...), you can use coerce and funcall with its result. This includes macroexpansions, although you may want to use macroexpand-1 rather than macroexpand, because lambda is already a macro, so if you expand too far, (lambda () ...) turns into (function (lambda () ...)).
CL-USER> (defmacro my-constantly (value)
`(lambda () ,value))
MY-CONSTANTLY
CL-USER> (macroexpand-1 '(my-constantly 36))
(LAMBDA () 36)
T
CL-USER> (funcall (coerce (macroexpand-1 '(my-constantly 36)) 'function))
36
If you try that with the plain macroexpand, though, there's a problem. Consider yourself warned:
CL-USER> (macroexpand '(my-constantly 36))
#'(LAMBDA () 36) ; not a list, but a function
T
CL-USER> (funcall (coerce (macroexpand '(my-constantly 36)) 'function))
; Error. :(
I think this is a case where you will find that the REPL is your friend. To get you started:
cl-user> (defmacro foo () #'(lambda () :hi))
foo
cl-user> (foo)
#<Compiled-function (:internal foo) (Non-Global) #x3020014F82FF>
cl-user> (funcall *)
:hi
cl-user> (macroexpand '(foo))
#<Compiled-function (:internal foo) (Non-Global) #x3020014F82FF>
t
cl-user> (funcall *)
:hi
cl-user>
I'll note in passing that the lambda form that appears in your example takes an argument, while your funcall doesn't provide one.
There are several issues with this. First I think this is a XY problem so if you show more of your problem I guess we might find a solution for it.
It has nothing with unquoting since when evaluation a quoted expression it's not longer quoted, but it's turn into data representation of the original quoted expression. You must eval data if you want to run it.
With eval you won't get the current lexical scope. So since you mention eval and lexical environment in the same post makes me thing you won't get what you want.
Now it's no problem making a list of functions, like this:
(list (lambda (x) (+ x x))
This is not quoted since I use list and teh lambda is evaluated to a closure. If it was assigned to variable x you could call it with (funcall (car x) 10)) ; ==> 20
EDIT
I actually made the same error message with this code:
(defmacro test () '#'(lambda (x) x))
(macroexpand '(test)) ; ==> #'(lambda (x) x) ; t
(funcall (macroexpand '(test)) 5) ; ==>
*** - funcall: #'(lambda (x) x) is not a function name; try using a symbol
instead
It doesn't work since you cannot call a lambda unevaluated. You need to call the closure (function) which is the result of the evaluation of the lambda form. If you would instead not quote it you'll have that evaluation in the macro:
(defmacro test () #'(lambda (x) x))
(macroexpand '(test)) ; ==> #<function :lambda (x) x> ;
(funcall (macroexpand '(test)) 5) ; ==> 5
Actually I cannot see why you would need to make this a macro. Lets make it a function instead.
(defun test () #'(lambda (x) x))
(funcall (test) 5 ) ; ==> 5
Even if this was more comples in most cases you would do with a closure.
Suppose I have this wonderful function foo
[92]> (defun foo () (lambda() 42))
FOO
[93]> (foo)
#<FUNCTION :LAMBDA NIL 42>
[94]>
Now, suppose I want to actually use foo and return 42.
How do I do that? I've been scrounging around google and I can't seem to come up with the correct syntax.
You want the FUNCALL function:
* (defun foo () (lambda () 42))
FOO
* (funcall (foo))
42
The relevant terms here are "Lisp-1" and "Lisp-2".
Your attempt at calling would work in a Lisp-1 like e.g. Scheme or Clojure.
Common Lisp is a Lisp-2 however which roughly means that variable names and function names are separate.
So, in order to call the function bound to a variable you either need to use the special forms funcall or apply as others have pointed out or set the function value of the symbol foo rather than the variable value.
The former basically takes the variable value of the symbol, assumes/checks that value is a function and then calls the function (with whatever arguments you passed to funcall/apply.
You don't really want to do the latter as that is quite silly in all but very specialised cases, but for completness sake this is roughly how you'd do it:
CL-USER> (setf (symbol-function 'foo) (lambda () 42))
#<FUNCTION (LAMBDA ()) {C43DCFD}>
CL-USER> (foo)
42
You should also want to look into the labels and flet special forms (which are commonly used) - there you actually do use the latter methods (these forms create a temporary function binding for symbols).
So your problem would there look like this:
(flet ((foo ()
42))
(foo))
i.e. here you temporarily bind the function value of the symbol foo to the function returning 42. Within that temporary context you can then call (foo) like regular global functions.
Your function foo returns a function. Use the funcall function to apply a function to arguments, even if the argument set is empty.
Here you can see that foo returns a value of type function:
CL-USER> (let ((f (foo)))
(type-of f))
FUNCTION
CL-USER> (let ((f (foo)))
(funcall f))
42
CL-USER> (type-of (foo))
FUNCTION
CL-USER> (funcall (foo))
42
Another option besides FUNCALL is APPLY:
(apply (foo) nil)
FUNCALL is the idiomatic way here, but you'll need APPLY when you have a list of parameters.