I figured that since Emacs Lisp and Common Lisp seemed so closely related syntax wise, I could just follow the example code I found on RosettaCode, but it turns out that I was wrong.
The code in question looks like this:
(defun print-name (&key first (last "?"))
(princ last)
(when first
(princ ", ")
(princ first))
(values))
And according to RosettaCode it should do the following:
> (print-name)
?
> (print-name :first "John")
?, John
> (print-name :last "Doe")
Doe
> (print-name :first "John" :last "Doe")
Doe, John
Now, here's the thing; whenever I try to run that function in my ELisp interpreter, I get the following error:
*** Eval error *** Wrong number of arguments: (lambda (&key first (last "?")) (princ la\
st) (if first (progn (princ ", ") (princ first))) (values)), 0
I'm not routined enough in lisp to know what that's supposed to mean, and no amount of Googling has lead me any closer to an answer.
So what's the correct way of doing this in Emacs Lisp?
What are arguments? Lisp programming is all about defining functions. Functions are general-purpose chunks of a program, and the arguments to a function are the specific data that you ask the function to deal with when you call the function.
Use defun to define your own functions in LISP. Defun requires you to provide three things. The first is the name of the function, the second is a list of parameters for the function, and the third is the body of the function -- i.e. LISP instructions that tell the interpreter what to do when the function is called.
In Common Lisp apply is a function that applies a function to a list of arguments (note here that "+" is a variadic function that takes any number of arguments): (apply #'+ (list 1 2)) Similarly in Scheme: (apply + (list 1 2))
This function can be run simply. The command [Alt][x] is used to a run a function interactively. Typing [Alt][x] switches the focus in Emacs to the minibuffer - if you then type in a function name it will be executed. To run doodlebug simply type [Alt][x] and then doodlebug.
Since Emacs Lisp does not support keyword arguments directly, you'll need to emulate these, either with cl-defun
as in the other answer, or by parsing the arguments as plist:
(defun print-name (&rest args)
(let ((first (plist-get args :first))
(last (or (plist-get args :last) "?")))
(princ last)
(when first
(princ ", ")
(princ first))))
&rest args
tells Emacs to put all function arguments into a single list. plist-get
extracts a value from a property list, that is, a list of the format (key1 value1 key2 value2 …)
. Effectively, a plist is a flattened alist.
Together this lets you call print-name
just like in your question:
> (print-name)
?
> (print-name :first "John")
?, John
> (print-name :last "Doe")
Doe
> (print-name :first "John" :last "Doe")
Doe, John
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With