Why there is no syntax sugar for funcall? We need it a lot. Won't it be great to write something like (&#do-something arg0 arg1 arg2) instead of (funcall do-something arg0 arg1 arg2) Why not add something like Ruby's &:method notation? Is there something already in the language?
There's nothing like that built into the language; you can easily assign the function to an additional name though, and use that. E.g., if you want to use &, you can:
CL-USER> (setf (symbol-function '&) (symbol-function 'funcall))
#<FUNCTION FUNCALL>
CL-USER> (&'list 1 2 3)
(1 2 3)
CL-USER> (&'cons 'x 'y)
(X . Y)
(There was a recent question on Stack Overflow about different ways to do that first line: How to stop evaluating lisp form when passed as function parameter?.)
Won't it be great to write something like (&#do-something arg0 arg1 arg2) instead of (funcall do-something arg0 arg1 arg2)?
Probably not. Common Lisp is a language that prefers expressive names for functions and macros. The name funcall is recognized, and it makes it clear that there's an indirect function call happening. Why would we want to obscure that? Evidently most people find funcall has the right balance between "short enough to write" and "long enough to be descriptive".
Why there is no syntax sugar for funcall?
You might call macros "syntax sugar" in Common Lisp, but there's no need for it here. Funcall is a function, not a special form or macro, so it's really very easy to alias it with another name, as shown above. The fact that most people don't do this should say something about how desirable it is.
There is no syntax for funcall, because we don't need it a lot (or else, define "we"). I mean, in a Lisp-2, such as Common Lisp, that's the trade-off, and unless you're doing some heavy lambda calculus, you get used to it.
If you really want to use a more succint syntax, you can define a dispatch macro character:
(set-dispatch-macro-character
#\# #\&
#'(lambda (stream subchar arg)
(let ((args-var (gensym)))
`(lambda (&rest ,args-var)
(declare (dynamic-extent ,args-var))
(apply ,(read stream t nil t) ,args-var)))))
(let ((my-function #'max))
(#&my-function 1 3 2))
Check if your compiler will optimize lambda forms and dynamic-extent &rest arguments passed to apply.
I advise against defining the single character & as a macro character, because it's a constituent character mostly used in the symbols &optional, &rest, &key, &allow-other-keys, &aux, &whole, &body and &environment.
If you're inclined to black magic:
(defun black-magic (stream sub-char numarg)
(declare (ignore sub-char numarg))
`(funcall ,#(read stream)))
(set-dispatch-macro-character
#\# #\! #'black-magic)
Rough example:
CL-USER> (defun foo (fn x y z)
#!(fn x y z))
FOO
CL-USER> (foo #'* 1 2 3)
6
CL-USER> (foo #'+ 1 1 1)
3
(It's better to use apply however... but it's even better to keep things simple and use nothing of this sort.)
Of couse we anyone can define something like that by reader macros, but i think it's not a very good idea to do such thing if you expecting than someone will read your code somtime.
Actually this sort of reader macro is syntactic sugar you're asking for. Do you reject your own idea now? Every time, when you use non-conventional syntactic sugar, you probably make things worse for your future code-readers.
Related
This question is somewhat related to an earlier one on programmatically generating symbol macros. I'm using that function in a convenience macro that throws undefined variable warnings. This macro and function:
(defmacro define-data (d body &optional doc)
(if (and doc (not (stringp doc))) (error "Documentation is not a string"))
`(let* ((d-str (string ',d))
(old-package *package*)
(*package* (if (find-package d-str) ;exists?
(find-package d-str) ;yes, return it
(make-package d-str)))) ;no, make it
;; Should we have an eval-when (:compile-toplevel) here?
(defparameter ,d ,body ,doc)
(export ',d old-package)
(define-column-names ,d)))
(defun define-column-names (d)
(maphash #'(lambda (key index)
(eval `(cl:define-symbol-macro ,key (cl:aref (columns ,d) ,index))))
(ordered-keys-table (slot-value d 'ordered-keys))))
are intended to be like defparameter, but additionally set up a few niceties for the user by defining:
a package with the name of d
a parameter in the current package with the data that will be sucked in by body
symbol-macros in package d for access to the individual data vectors
If I use defparameter from the REPL, and then call define-column-names, all is well. However when using the macro I get:
; in: DEFINE-COLUMN-NAMES FOO
; (DEFINE-COLUMN-NAMES CL-USER::FOO)
;
; caught WARNING:
; undefined variable: CL-USER::FOO
I suspect that this is because the compiler has no way of knowing that FOO will actually be defined when define-symbol-macro is called. Everything works fine, but I don't want the warning to frighten users, so am thinking of suppressing it. I hate suppressing warnings though, so thought I'd come here for a second opinion.
EDIT: I've marked an answer correct because it does correctly answer the question as asked. For an answer to the problem see my comments.
My answer to the 'when to muffle warnings' question in the title is: if it's your own code then never, under any circumstances. If it is someone else's code, then rewrite it not to warn unless you can't.
As to solving the problem I haven't thought about this hard enough, but the problem is that you definitely want the defparameter to be at top-level so the compiler can see it, and it can't really be if it's inside a let. But you can raise it to toplevel trivially since it depends on nothing inside the let.
I am then pretty certain that you want the rest of the macro to happen at compile time, because you definitely want the symbol-macros available at compile-time. So an attempt at the first macro would be (note I've fixed the handling of the docstring: (defparameter foo 1 nil) is bad):
(defmacro define-data (d body &optional doc)
(when (and doc (not (stringp doc)))
(error "Documentation is not a string"))
`(progn
(defparameter ,d ,body ,#(if doc (list doc) '()))
(eval-when (:compile-toplevel :load-toplevel :execute)
(let* ((d-str (string ',d))
(old-package *package*)
(*package* (if (find-package d-str) ;exists?
(find-package d-str) ;yes, return it
(make-package d-str)))) ;no, make it
(export ',d old-package)
(define-column-names ,d)))))
As a side note: although I think the fact that programmatically defining symbol macros is hard because CL left that out for some reason, I think I'd personally use some other approach rather than this, because eval is just so horrid. That's just me however: if you want to do this you do need eval I think (it is very rare that this is true!).
I am not sure exactly how define-columns-names works so I replaced it with a stub function that returns d.
Note also that you can use check-type and should try not injecting symbols in generated code, this introduces potential variable capture that can be avoided with gensym.
As far as I know you cannot use eval-when as suggested by your comment (see Issue EVAL-WHEN-NON-TOP-LEVEL Writeup for details).
But I have no warning if I declare the symbol as being special around the call.
(defmacro define-data (d body &optional doc)
(check-type doc (or null string))
(check-type d symbol)
(let ((d-str (string d)))
(alexandria:with-gensyms (old-package)
`(let* ((,old-package *package*)
(*package* (if (find-package ,d-str) ;exists?
(find-package ,d-str) ;yes, return it
(make-package ,d-str)))) ;no, make it
(defparameter ,d ,body ,doc)
(export ',d ,old-package)
(locally (declare (special ,d))
(define-column-names ,d))))))
It is also a bit strange that you expand into a call to define-column-names, which in turns evaluated a form built at runtime. I think it might be possible to do all you want during macroexpansion time, but as said earlier what you are trying to do is a bit unclear to me. What I have in mind is to replace define-column-names by:
,#(expand-column-names-macros d)
... where expand-column-names-macros builds a list of define-symbol-macro forms.
Is there a way, in common lisp, to receive a user input, say "foo", and defvar a global variable *foo*?
For example (which does NOT work):
(defun global-name (s)
"Takes s and changes it to *s*"
(concatenate 'string "*" s "*"))
(defun add-global-var (var)
"defvars a global variable and adds it to *global-list*"
(let ((var-name (global-name var)))
(defvar var-name var)
(push var-name *global-list*)))
; Used like this:
(add-global-var "myvar")
In this case, the var-name is a string, and will not work with defvar.
Déjà vu... I asked these kinds of questions 20+ years ago ;-)
Your question
Yes, you can do that (but no, you do not want to!)
(defun add-global-var (var-name &optional (package *package*))
(let ((var (intern var-name package)))
(proclaim `(special ,var))
(push var *global-list*)))
Please see
proclaim
intern
*package*
Alternatively, you can use a macro as the other answer suggests - in
fact, symbol creation at macroexpansion time (which is part of
compilation) is a very common thing,
cf. gensym.
Your problem
There is little reason to do this though.
Global variables created at run time were not available at compile time
and are, therefore, pretty useless.
Why do you want to do this?
If you want to map strings to values, you are much better off using an
equal hash table.
If you want to integrate with read,
you should call it while binding
*package*
to your internal temp package and then use
symbol-value
to store and retrieve values.
You will use intern to
map "variable names" to the symbols.
This is most likely a XY problem since it's very unusual to need to make a variable with a name made up in runtime. It's very common in compile time, but not runtime. #coredump has already covered compile time macros if that is what you are after.
Here is how you do it though:
(defun add-global-var (var)
"defvars a global variable and adds it to *global-list*"
(let ((var-name (intern (string-upcase (global-name var)))))
(set var-name var)
(push var-name *global-list*)))
set is deprecated, but I doubt it will ever be removed. Implementations might not be able to run as fast though since this is like messing with internals.
Since the names are not from source you you have no good use for the bidnings. because of this I would rather use a hash:
(defvar *bindings* (make-hash-table :test #'eq))
(defun add-binding (var)
(let ((var-name (intern (string-upcase (global-name var)))))
(setf (gethash var-name *bindings*) var)
*bindings*))
A reason to do this is as a part of your own little interpreter symbol table or something. You don't need a list of them since you can get all the keys from the hash as well as get the bound values.
Yes, with a macro:
(defvar *global-list* nil)
I changed global-name so that it also accepts symbols, to avoid thinking about whether the string should be upcased or not. With a symbol, the case is given by readtable-case (you can use uninterned symbols if you want to avoid polluting packages).
(defun global-name (name)
(check-type name (or string symbol))
(intern
(concatenate 'string "*" (string name) "*")))
I named the macro defvar*:
(defmacro defvar* (name)
`(push
(defvar ,(global-name name) ',name)
*global-list*))
Tests:
CL-USER> (defvar* #:foo)
(*FOO*)
CL-USER> (defvar* #:bar)
(*BAR* *FOO*)
Note:
You can also add an optional package argument like in #sds's answer, that's better.
So consider the following code:
(define-condition some-condition (error) nil)
(defmethod print-object ((obj some-condition) stream)
(format stream "HELLO THERE"))
(defmacro error-report-test-aux (fn-to-cause-error error-type-to-catch fn-to-handle-error expected-message)
`(let ((result-message
(handler-case (funcall ,fn-to-cause-error)
(,error-type-to-catch (e) (funcall ,fn-to-handle-error e)))))
(assert (string= result-message
,expected-message))
t))
I can use it like so:
(error-report-test-aux (lambda () (error 'some-condition))
some-condition
#'princ-to-string
"HELLO THERE")
But I wanted to make error-report-test-aux a function instead of macro, so that i can pass to it a type of condition within a variable.
To simply write defun instead of defmacro and remove backquote and commas doesn't work because handler-case is macro and it doesn't evaluate error-type-to-catch.
My question is: Is there something like handler-case that would evaluate it's arguments (specifically condition type argument)?
Yes and no :-)
No to your exact question
There is no standard function that would do what you want because catching errors requires establishing bindings and one usually want to bind constant symbols (like in let/let*) because it is easier to optimize.
You might consider creating a "universal" handler using handler-bind and then declining to handle "uninteresting" conditions (as suggested by #jkiiski in comments), but I am not sure if that fits your exact requirements (untested!):
(defun error-report-test-aux (fn-to-cause-error error-type-to-catch expected-message)
(catch 'trap
(handler-bind ((error
(lambda (condition)
(when (typep condition error-type-to-catch)
(throw 'trap (string= (princ-to-string condition)
expected-message))))))
(funcall fn-to-cause-error))))
Yes, implementation-specific
IF your implementation implements handler-case/handler-bind by binding an internal global variable, you can use progv to bind it yourself and thus implement your error-report-test-aux as a function.
This is probably not the best idea (your code becomes wedded to a specific implementation).
Yes, kinda
You can use the fact that some-condition names a CLOS class and use generic functions instead of the macro.
I'm reviving an old LISP program from the early 1980s.
(It's the Nelson-Oppen simplifier, an early proof system.
This version was part of the Ford Pascal-F Verifier,
and was running in Franz LISP in 1982.) Here's
the entire program:
https://github.com/John-Nagle/pasv/tree/master/src/CPC4
I'm converting the code to run under clisp on Linux,
and need some advice. Most of the problems are with
macros.
HUNKSHELL
Hunkshell was a 1970s Stanford SAIL hack to support records with named fields in LISP. I think I've converted this OK; it seems to work.
https://github.com/John-Nagle/pasv/blob/master/src/CPC4/hunkshell.l
The original macro generated more macros as record update functions.
I'm generating defuns. Is there any reason to generate macros?
By the way, look at what I wrote for "CONCAT". Is there a better way
to do that?
DEFMAC
More old SAIL macros, to make macro definition easier before defmacro became part of the language.
https://github.com/John-Nagle/pasv/blob/master/src/CPC4/defmac.l
I've been struggling with "defunobj". Here's my CL version, partly converted:
; This macro works just like defun, except that both the value and the
; function-binding of the symbol being defined are set to the function
; being defined. Therefore, after (defunobj f ...), (f ...) calls the
; defined function, whereas f evaluates to the function itself.
;
(defmacro defunobj (fname args &rest b)
`(progn
(defun ,fname ,args ,b)
;;;;(declare (special ,fname)) ;;;; ***declare not allowed here
(setq ,fname (getd ',fname))))
If I made that declare a proclaim, would that work right?
And what replaces getd to get a function pointer?
SPECIAL
There are lots of (DECLARE (SPECIAL FOO)) declarations at top
level in this code. That's not allowed in CL. Is it
appropriate to use (PROCLAIM (SPECIAL FOO)) instead?
Concat
Essentially correct, but indentation is broken (like everywhere else - I suggest Emacs to fix it).
Also, you don't need the values there.
defunobj
I suggest defparameter instead
of setq. Generally speaking, before setting a variable (with, e.g., setq) one should establish it (with, e.g., let or defvar).
fdefinition is what
you are looking for instead of getd.
I also don't think you are using backquote right:
(defmacro defunobj (fname &body body)
`(progn
(defun ,fname ,#body)
(defparameter ,fname (fdefinition ',fname))))
Special
I think defvar and defparameter
are better than proclaim
special.
PS. Are you aware of the CR.se site?
I've just been reading up on the sharpsign colon reader macro and it sounded like it had a very similar effect to gensym
Sharpsign Colon: "introduces an uninterned symbol"
Gensym: "Creates and returns a fresh, uninterned symbol"
So a simple test
CL-USER> #:dave
; Evaluation aborted on #<UNBOUND-VARIABLE DAVE {1002FF77D3}>.
CL-USER> (defparameter #:dave 1)
#:DAVE
CL-USER> #:dave
; Evaluation aborted on #<UNBOUND-VARIABLE DAVE {100324B493}>.
Cool so that fails as it should.
Now for the macro test
(defmacro test (x)
(let ((blah '#:jim))
`(let ((,blah ,x))
(print ,blah))))
CL-USER> (test 10)
10
10
CL-USER>
Sweet so it can be used like in a gensym kind of way.
To me this looks cleaner than gensym with an apparently identical result. I'm sure I'm missing a vital detail so my question is, What it it?
Every time the macro is expanded, it will use the same symbol.
(defmacro foo () `(quote #:x))
(defmacro bar () `(quote ,(gensym)))
(eq (foo) (foo)) => t
(eq (bar) (bar)) => nil
Gensym will create a new symbol every time it is evaluated, but sharp colon will only create a new symbol when it is read.
While using sharp colon is unlikely to cause problems, there are a couple rare cases where using it would lead to nearly impossible to find bugs. It is better to be safe to begin with by always using gensym.
If you want to use something like sharp colon, you should look at the defmacro! macro from Let Over Lambda.
GENSYM is like MAKE-SYMBOL. The difference is that GENSYM supports fancy naming by counting up -> thus symbols kind of have unique names, which makes debugging a bit easier when having gensyms for example in macro expansions.
#:foo is a notation for the reader.
So you have a function which creates these and a literal notation. Note that, when *print-circle* is true, some kind of identity maybe preserved in s-expressions: #(#1=#:FOO #1#).
Generally this is similar to (a . b) and (cons 'a 'b), #(a b) and (vector 'a 'b)... One is literal data and the other one is a form which will create ('cons') fresh objects.
If you look at your macro, the main problem is that nested usage of it could cause problems. Both lexically or dynamically.
lexically it could be the same variable, which is rebound.
dynamically, if it is a special variable it could also be rebound
Using a generated symbol at macro expansion time would make sure that different and expanded code would not share bindings.