I'm trying to write a macro in emacs lisp to create some ‘helper functions.’
Ultimately, my helper functions will be more useful than what I have here. I realize that there may be better/more intuitive ways to accomplish the same thing (please post) but my basic question is why won't this work/what am I doing wrong:
(defmacro deftext (functionname texttoinsert)
`(defun ,(make-symbol (concatenate 'string "text-" functionname)) ()
(interactive)
(insert-string ,texttoinsert)))
(deftext "swallow" "What is the flight speed velocity of a laden swallow?")
(deftext "ni" "What is the flight speed velocity of a laden swallow?")
If I take the output of the macroexpand and evaluate that, I get the interactive functions I was intending to get with the macro, but even though the macro runs and appears to evaluate, I can't call M-x text-ni or text-swallow.
This does what you want:
(defmacro deftext (functionname texttoinsert)
(let ((funsymbol (intern (concat "text-" functionname))))
`(defun ,funsymbol () (interactive) (insert-string ,texttoinsert))))
As has been pointed out, the solution is to use intern instead of make-symbol.
It's possible to create multiple independent symbols with the same name, but only one of them can be the canonical symbol for the given name -- i.e. the symbol you will obtain when you refer to it elsewhere.
intern returns the canonical symbol for the given name. It creates a new symbol only if no interned symbol by that name already exists. This means that it will only ever create one symbol for any given name1.
make-symbol, on the other hand, creates a new symbol every time it is called. These are uninterned symbols -- each one is a completely valid and functional symbol, but not the one which will be seen when you refer to a symbol by its name.
See: C-hig (elisp) Creating Symbols RET
Because defun returns the symbol it sets, you can observe what's going on by capturing the return value and using it as a function:
(defalias 'foo (deftext "ni" "What is the flight speed velocity of a laden swallow?"))
M-x text-ni ;; doesn't work
M-x foo ;; works
or similarly:
(call-interactively (deftext "shrubbery" "It is a good shrubbery. I like the laurels particularly."))
The tricky part in all this -- and the reason that evaluating the expanded form did what you wanted, and yet the macro didn't -- is to do with exactly how and when (or indeed if) the lisp reader translates the name of the function into a symbol.
If we write a function foo1:
(defun foo1 (texttoinsert) (insert-string texttoinsert))
The lisp reader reads that as text, and converts it into a lisp object. We can use read-from-string to do the same thing, and we can look at the printed representation of the resulting lisp object:
ELISP> (car (read-from-string "(defun foo1 (texttoinsert) (insert-string texttoinsert))"))
(defun foo1
(texttoinsert)
(insert-string texttoinsert))
Within that object, the function name is the canonical symbol with the name "foo1". Note, however, that the return value we see from read-from-string is only the printed representation of that object, and the canonical symbol is represented only by its name. The printed representation does not enable us to distinguish between interned and uninterned symbols, as all symbols are represented only by their name.
(Skipping ahead momentarily, this is the source of your issue when evaluating the printed expansion of your macro, as that printed form is passed through the lisp reader, and what was once an uninterned symbol becomes an interned symbol.)
If we then move on to macros:
(defmacro deffoo2 ()
`(defun foo2 (texttoinsert) (insert-string texttoinsert)))
ELISP> (car (read-from-string "(defmacro deffoo2 ()
`(defun foo2 (texttoinsert) (insert-string texttoinsert)))"))
(defmacro deffoo2 nil
`(defun foo2
(texttoinsert)
(insert-string texttoinsert)))
This time the reader has read the macro definition into a lisp object, and within that object is the canonical symbol foo2. We can verify this by inspecting the object directly:
ELISP> (eq 'foo2
(cadr (cadr (nth 3
(car (read-from-string "(defmacro deffoo2 ()
`(defun foo2 () (insert-string texttoinsert)))"))))))
t
So for this macro, it is already dealing with that canonical symbol foo2 before any macro call/expansion happens, because the lisp reader established that when reading the macro itself. Unlike our previous simple function definition (in which the function symbol was determined by the lisp reader as the function was defined), when a macro is called & expanded the lisp reader is not utilised. The macro expansion is performed using pre-existing lisp objects -- no reading is necessary.
In this example the function symbol is already present in the macro, and because it is the canonical symbol we could use (foo2) elsewhere in our code to call that function. (Or, had I made the definition interactive, use M-x foo2.)
Finally getting back to the original macro from the question, it's obvious that the lisp reader never encounters a function name symbol for the function it will define:
ELISP> (car (read-from-string "(defmacro deftext (functionname texttoinsert)
`(defun ,(make-symbol (concatenate 'string \"text-\" functionname)) ()
(interactive)
(insert-string ,texttoinsert)))"))
(defmacro deftext
(functionname texttoinsert)
`(defun ,(make-symbol
(concatenate 'string "text-" functionname))
nil
(interactive)
(insert-string ,texttoinsert)))
Instead this object produced by the lisp reader contains the expression ,(make-symbol (concatenate 'string "text-" functionname)); and that backquoted expression will be evaluated at expansion time to create a new uninterned symbol which will be a part of the object created by that expansion.
In our earlier examples the resulting object had a car of defun (interned), and a cadr of foo1 or foo2 (both also interned).
In this last example, the object has a car of defun (interned) but a cadr of an uninterned symbol (with the name resulting from the concatenate expression).
And finally, if you print that object, the printed representation of that uninterned function symbol will be the symbol name, and reading that printed representation back by evaluating it would cause the function cell for the canonical symbol to be defined instead.
1 In fact the unintern function can be used to unintern a symbol, after which calling intern for the same name would naturally create a new symbol; but that's not important for this discussion.
FWIW, if you use lexical-binding, you don't need to use a macro:
(defun deftext (functionname texttoinsert)
(defalias (intern (concat "text-" functionname))
(lambda ()
(interactive)
(insert-string texttoinsert))))
It's been years, but I think you're probably missing an fset to define the function; see the docs if you are wanting it a compile time too.
Related
I'm a Lisp beginner and I'm struggling to understand why the following code gives me an error.
(dolist (elem '(mapcar
mapcon))
(when (fboundp `',elem) (print "hello")))
Thanks.
Edit:
A bit more context. I wrote the following in Elisp and I don't know how to fix it.
(dolist (ui-elem '(menu-bar-mode
tool-bar-mode
tooltip-mode
scroll-bar-mode
horizontal-scroll-bar-mode))
(when (fboundp `',ui-elem) (ui-elem -1)))
Note
In your question you mix common-lisp and elisp, but they are two different languages. The question however touches on concepts that are identical in both languages.
The need to quote symbols
The code you want to write checks if a symbol is bound to a function.
What you already know probably is that you can call fboundp on a symbol to determines this:
(fboundp 'menu-bar-mode)
=> t
When you evalute the above form, 'menu-bar-mode is the same as (quote menu-bar-mode), and is evaluated as the symbol object menu-bar-mode. This is the value that is given as an argument to fboundp.
In you example you want to iterate over a list of symbols, call fboundp on it and call the function if the symbol denotes a function. You can do this as follows:
(dolist (s '(menu-bar-mode and other symbols))
(when (fboundp s)
(funcall s -1)))
The list of symbols '(menu-bar-mode and other symbols) is quoted, which means that when dolist evaluates it, it sees a list of symbols. The value to which s is bound at each iteration of the loop is a symbol object, there is no need to quote them.
Quoting a symbol is something you have to do when writing them in your code so that they are not interpreted as variables. When you iterate over a list of symbols, you already manipulate symbols.
Note also that both Common Lisp and Emacs Lisp are "Lisp-2", meanings that you have to use (funcall ui-elem -1) instead of writing (ui-elem -1). When you write the latter form, that means calling the function literally named ui-elem because for function application, the first symbol in the list is not evaluated, it is taken literally.
Too many levels of quoting
The actual error I have when I execute your code is:
(wrong-type-argument symbolp 'mapcar)
It may look like 'mapcar denotes a symbol, because when you want the interpreter to evaluate some code as a symbol, you need to quote it. However, Lisp printers write objects in a way that they can be read back to "similar" objects. The error message that is printed if I expect a symbol to be a number is the following, where symbol foo is printed unquoted:
(+ 'foo 3)
;; error: (wrong-type-argument number-or-marker-p foo)
In your error message, the form that you are trying to use as a symbol is (quote mapcar). Recall that when you directly call fboundp:
(fboundp 'mapcar)
It is the same as-if you wrote:
(fboundp (quote mapcar))
First, (quote mapcar) is evaluated, as the symbol mapcar. Then, fboundp is applied to that value.
But when you write the following, while ui-elem is bound to symbol mapcar:
(fboundp `',ui-elem)
This is equivalent to:
(fboundp `(quote ,ui-elem))
The argument to fboundp is evaluated as (quote mapcar). You have one extra level of quoting. You could write instead:
(fboundp `,ui-elem)
But then, you don't need to use backquote/comma, you can directly write:
(fboundp ui-elem)
I'm attempting to make a macro that will take an input stream and do something different depending on the contents of the first line read, and then read further input. I'm having trouble just having a macro that will take an input stream and read some values from it.
A contrived example:
(defmacro read-and-print (&optional in)
`(print
,(if (string= (read-line in) "greet")
`(concatenate 'string "hello" (read-line ,in))
`(read-line ,in))))
(with-input-from-string (in "greet
bob") (read-and-print in))
but even that is producing the following error
There is no applicable method for the generic function
#<STANDARD-GENERIC-FUNCTION SB-GRAY:STREAM-READ-LINE (1)>
when called with arguments
(IN).
[Condition of type SB-INT:COMPILED-PROGRAM-ERROR]
The thing that's really baffling me is even changing the function to take a string for the first line isn't working:
(defmacro read-and-print (command &optional in)
`(print
,(if (string= command "greet")
`(concatenate 'string "hello " (read-line ,in))
`(read-line ,in))))
(with-input-from-string (in "greet
bob")
(read-and-print (read-string in) in))
This gives me
The value
(READ-LINE IN)
is not of type
(OR (VECTOR CHARACTER) (VECTOR NIL) BASE-STRING SYMBOL CHARACTER)
when binding SB-IMPL::STRING1
[Condition of type SB-INT:COMPILED-PROGRAM-ERROR]
While this executes completely fine:
(with-input-from-string (in "greet
bob")
(read-and-print "greet" in))
Is there something special about the with-input-from-string macro that I'm missing? I suspect I'm missing something very obvious about macros, but googling has gotten me nowhere.
What you asked
Macros are a code generation tool.
They do not evaluate their arguments.
Your with-input-from-string example works because strings are self-evaluating. If you quite the string literal, you will get an error.
What you should have asked
You do not need a macro here. Use a function instead.
When deciding between a function and a macro, you need to ask yourself:
Am I defining a new syntax?
Does the code generate more code?
Unless you understand the questions and answer yes, you should be using functions.
See also How does Lisp let you redefine the language itself?
Your macro:
(defmacro read-and-print (&optional in)
`(print
,(if (string= (read-line in) "greet")
`(concatenate 'string "hello" (read-line ,in))
`(read-line ,in))))
But ,(if ... in ...) makes no sense, since the value of in typically isn't a stream at macro expansion time, but code (a symbol, an expression, ...). Since your code is not executing and the macro sees the source (and not the values of something which has not been executed yet) you can't do that. You can't also not usefully repair that: It's just the wrong approach. Use a function instead.
Use a function:
CL-USER 17 > (defun read-and-print (&optional in)
(if (string= (read-line in) "greet")
(concatenate 'string "hello" (read-line in))
(read-line in)))
READ-AND-PRINT
CL-USER 18 > (with-input-from-string (in "greet
foo
bar")
(read-and-print in))
"hellofoo"
Using a macro
You still can write it as a macro, but then you need to generate the code so that it runs at runtime, and not at macro-expansion time:
(defmacro read-and-print (&optional in)
`(print
(if (string= (read-line ,in) "greet")
(concatenate 'string "hello" (read-line ,in))
(read-line ,in))))
Note: one would actually might want to handle that in is not evaluated multiple times.
This macro would give you the advantage that the code is inlined.
This macro would give you the disadvantage that the code is inlined.
The function above gives you the advantage that the code typically is not inlined.
The function above gives you the advantage that the code can optionally be inlined, by telling the compiler to do so with an inline declaration.
The Lisp forum thread Define macro alias? has an example of creating function alias using a form such as
(setf (symbol-function 'zero?) #'zerop)
This works fine, making zero? a valid predicate. Is it possible to parametrize this form without resorting to macros? I'd like to be able to call the following and have it create function?:
(define-predicate-alias 'functionp)`
My take was approximately:
(defun defalias (old new)
(setf (symbol-function (make-symbol new))
(symbol-function old)))
(defun define-predicate-alias (predicate-function-name)
(let ((alias (format nil "~A?" (string-right-trim "-pP" predicate-function-name))))
(defalias predicate-function-name alias)))
(define-predicate-alias 'zerop)
(zero? '())
This fails when trying to call zero? saying
The function COMMON-LISP-USER::ZERO? is undefined.
make-symbol creates an uninterned symbol. That's why zero? is undefined.
Replace your (make-symbol new) with e.g. (intern new *package*). (Or you may want to think more carefully in which package to intern your new symbol.)
Your code makes a symbol, via MAKE-SYMBOL, but you don't put it into a package.
Use the function INTERN to add a symbol to a package.
To expand on Lars' answer, choose the right package. In this case the default might be to use the same package from the aliased function:
About style:
Anything that begins with DEF should actually be a macro. If you have a function, don't use a name beginning with "DEF". If you look at the Common Lisp language, all those are macro. For example: With those defining forms, one would typically expect that they have a side-effect during compilation of files: the compiler gets informed about them. A function can't.
If I put something like this in a file
(define-predicate-alias zerop)
(zero? '())
and then compile the file, I would expect to not see any warnings about an undefined ZERO?. Thus a macro needs to expand (define-predicate-alias 'zerop) into something which makes the new ZERO? known into the compile-time environment.
I would also make the new name the first argument.
Thus use something like MAKE-PREDICATE-ALIAS instead of DEFINE-PREDICATE-ALIAS, for the function.
There are already some answers that explain how you can do this, but I'd point out:
Naming conventions, P, and -P
Common Lisp has a naming convention that is mostly adhered to (there are exceptions, even in the standard library), that if a type name is multiple words (contains a -), then its predicate is named with -P suffix, whereas if it doesn't, the suffix is just P. So we'd have keyboardp and lcd-monitor-p. It's good then, that you're using (string-right-trim "-pP" predicate-function-name)), but since the …P and …-P names in the standard, and those generated by, e.g., defstruct, will be using P, not p, you might just use (string-right-trim "-P" predicate-function-name)). Of course, even this has the possible issues with some names (e.g., pop), but I guess that just comes with the territory.
Symbol names, format, and *print-case*
More importantly, using format to create symbol names for subsequent interning is dangerous, because format doesn't always print a symbol's name with the characters in the same case that they actually appear in its name. E.g.,
(let ((*print-case* :downcase))
(list (intern (symbol-name 'foo))
(intern (format nil "~A" 'foo))))
;=> (FOO |foo|) ; first symbol has name "FOO", second has name "foo"
You may be better off using string concatenation and extracting symbol names directly. This means you could write code like (this is slightly different use case, since the other questions already explain how you can do what you're trying to do):
(defmacro defpredicate (symbol)
(flet ((predicate-name (symbol)
(let* ((name (symbol-name symbol))
(suffix (if (find #\- name) "-P" "P")))
(intern (concatenate 'string name suffix)))))
`(defun ,(predicate-name symbol) (x)
(typep x ',symbol)))) ; however you're checking the type
(macroexpand-1 '(defpredicate zero))
;=> (DEFUN ZEROP (X) (TYPEP X 'ZERO))
(macroexpand-1 '(defpredicate lcd-monitor))
;=> (DEFUN LCD-MONITOR-P (X) (TYPEP X 'LCD-MONITOR))
I have following code which confuse me now, I hope some can tell me the difference and how to fix this.
(defmacro tm(a)
`(concat ,(symbol-name a)))
(defun tf(a)
(list (quote concat) (symbol-name a)))
I just think they should be the same effect, but actually they seem not.
I try to following call:
CL-USER> (tf 'foo)
(CONCAT "FOO")
CL-USER> (tm 'foo)
value 'FOO is not of the expected type SYMBOL.
[Condition of type TYPE-ERROR]
So, what's the problem?
What i want is:
(tm 'foo) ==> (CONCAT "FOO")
The first problem is that 'foo is expanded by the reader to (quote foo), which is not a symbol, but a list. The macro tries to expand (tm (quote foo)). The list (quote foo) is passed as the parameter a to the macro expansion function, which tries to get its symbol-name. A list is not a valid argument for symbol-name. Therefore, your macro expansion fails.
The second problem is that while (tm foo) (note: no quote) does expand to (concat "FOO"), this form will then be executed by the REPL, so that this is also not the same as your tf function. This is not surprising, of course, because macros do different things than functions.
First, note that
`(concat ,(symbol-name a))
and
(list (quote concat) (symbol-name a))
do the exact same thing. They are equivalent pieces of code (backquote syntax isn't restricted to macro bodies!): Both construct a list whose first element is the symbol CONCAT and whose second element is the symbol name of whatever the variable A refers to.
Clearly, this only makes sense if A refers to a symbol, which, as Svante has pointed out, isn't the case in the macro call example.
You could, of course, extract the symbol from the list (QUOTE FOO), but that prevents you from calling the macro like this:
(let ((x 'foo))
(tm x))
which raises the question of why you would event want to force the user of the macro to explicitly quote the symbol where it needs to be a literal constant anyway.
Second, the way macros work is this: They take pieces of code (such as (QUOTE FOO)) as arguments and produce a new piece of code that, upon macroexpansion, (more or less) replaces the macro call in the source code. It is often useful to reuse macro arguments within the generated code by putting them where they are going to be evaluated later, such as in
(defmacro tm2 (a)
`(print (symbol-name ,a)))
Think about what this piece of code does and whether or not my let example above works now. That should get you on the right track.
Finally, a piece of advice: Avoid macros when a function will do. It will make life much easier for both the implementer and the user.
I realized that a certain section of my code consists of groups of methods that look similar (like I have multiple trios: a helper function that gets called by two other functions meant for the programmer). I'm trying to write a macro that will define these three functions for me so that all I need to do is call the macro. But my attempt results in defuns and function calls that have quoted strings instead of the generated names as new symbols. What am I doing wrong?
Example (incorrect code)
(defmacro def-trio (base-name)
(let
((helper-name (format nil "helper-~a" base-name))
(method-1 (format nil "~a-1" base-name))
(method-2 (format nil "~a-2" base-name)))
`(progn
(defun ,helper-name () 'helper-called)
(defun ,method-1 () (,helper-name) '1-called)
(defun ,method-2 () (,helper-name) '2-called))))
Now the following happens:
(def-trio my-trio)
==>
(PROGN (DEFUN "helper-MY-TRIO" () 'HELPER-CALLED)
(DEFUN "MY-TRIO-1" () ("helper-MY-TRIO") '1-CALLED)
(DEFUN "MY-TRIO-2" () ("helper-MY-TRIO") '2-CALLED))
Also, after I learn how to get this working, are there any extra gotcha's if I had this macro define other macros instead of other functions? I read How do I write a macro-defining macro in common lisp but I think my question is a little different because I'm asking about programmatically generated symbols/names. I'm open to being corrected though :) Thanks!
Try this:
(defmacro def-trio (base-name) ; changes:
(let* ; 3.
((package (symbol-package base-name)) ; 2.
(helper-name (intern (format nil "HELPER-~a" base-name) package)) ; 1. 4.
(method-1 (intern (format nil "~a-1" base-name) package)) ; 1.
(method-2 (intern (format nil "~a-2" base-name) package)) ) ; 1.
`(progn
(defun ,helper-name () 'helper-called)
(defun ,method-1 () (,helper-name) '1-called)
(defun ,method-2 () (,helper-name) '2-called) )))
The following changes were made to your original definition -- the first change is the crucial one:
Interned each of computed symbol names into the same package as the base name using (intern ... package).
Introduced the variable package which is bound to the package of the supplied base-name symbol.
Changed let to let* to allow the newly introduced variable package to be referenced in subsequent variables.
Changed the prefix of the helper method to upper case to match the convention for normal Lisp symbols.
Use INTERN to turn the generated function name strings into symbols.