Emacs Lisp: how to avoid inserting a duplicate list item? - emacs

How do I check if a string is already in a list in Emacs Lisp? I need to check if a certain path string is already in exec-path, and then add it to that list if it's not.

The function add-to-list will check automatically before adding
(setq a '(1 2 3))
(add-to-list 'a 4)
(add-to-list 'a 3)
will result in a equal to (4 1 2 3)
From Emacs 26 C-h f add-to-list:
(add-to-list LIST-VAR ELEMENT &optional APPEND COMPARE-FN)
Add ELEMENT to the value of LIST-VAR if it isn’t there yet.
The test for presence of ELEMENT is done with ‘equal’, or with
COMPARE-FN if that’s non-nil.
If ELEMENT is added, it is added at the beginning of the list,
unless the optional argument APPEND is non-nil, in which case
ELEMENT is added at the end.
The return value is the new value of LIST-VAR.
This is handy to add some elements to configuration variables,
but please do not abuse it in Elisp code, where you are usually
better off using ‘push’ or ‘cl-pushnew’.
If you want to use ‘add-to-list’ on a variable that is not
defined until a certain package is loaded, you should put the
call to ‘add-to-list’ into a hook function that will be run only
after loading the package. ‘eval-after-load’ provides one way to
do this. In some cases other hooks, such as major mode hooks,
can do the job.

In addition to cobbal's answer about add-to-list, there's also cl-pushnew:
(require 'cl-lib)
(setq list-of-strings '("one" "two" "three"))
(cl-pushnew "two" list-of-strings :test #'string=)
⇒ ("one" "two" "three")
(cl-pushnew "zero" list-of-strings :test #'string=)
⇒ ("zero" "one" "two" "three")
The :test #'string= argument is needed in your case because, cl-pushnew uses eql to compare by default, and it doesn't treat two strings with the same content as equal. (equal) would work too.
(eql "some-string" "some-string")
⇒ nil
(string= "some-string" "some-string")
⇒ t
(equal "some-string" "some-string")
⇒ t
From Emacs 26 C-h f cl-pushnew:
cl-pushnew is a Lisp macro in ‘cl-lib.el’.
(cl-pushnew X PLACE [KEYWORD VALUE]...)
(cl-pushnew X PLACE): insert X at the head of the list if not already there.
Like (push X PLACE), except that the list is unmodified if X is ‘eql’ to
an element already on the list.
Keywords supported: :test :test-not :key

Related

What is atom in LISP?

I would like to have a clear understanding, what is 'Atom' in LISP?
Due to lispworks, 'atom - any object that is not a cons.'.
But this definition is not enough clear for me.
For example, in the code below:
(cadr
(caddar (cddddr L)))
Is 'L' an atom? On the one hand, L is not an atom, because it is cons, because it is the list (if we are talking about object, which is associated with the symbol L).
On the other hand, if we are talking about 'L' itself (not about its content, but about the symbol 'L'), it is an atom, because it is not a cons.
I've tried to call function 'atom',
(atom L) => NIL
(atom `L) => T
but still I have no clue... Please, help!
So the final question: in the code above, 'L' is an atom, or not?
P.S. I'm asking this question due to LISP course at my university, where we have a definition of 'simple expression' - it is an expression, which is atom or function call of one or two atomic parameters. Therefore I wonder if expression (cddddr L) is simple, which depends on whether 'L' is atomic parameter or not.
Your Lisp course's private definition of "simple expression" is almost certainly rooted purely in syntax. The idea of "atomic parameter" means that it's not a compound expression. It probably has nothing to do with the run-time value!
Thus, I'm guessing, these are simple expressions:
(+ 1 2)
42
"abc"
whereas these are not:
(+ 1 (* 3 4)) ;; (* 3 4) is not an atomic parameter
(+ a b c) ;; parameters atomic, but more than two
(foo) ;; not simple: fewer than one parameter, not "one or two"
In light of the last counterexample, it would probably behoove them to revise their definition.
On the one hand, L is not an atom, because it is cons, because it is the list (if we are talking about object, which is associated with the symbol L).
You are talking here about the meaning of the code being executed, its semantics. L here stands for a value, which is a list in your tests. At runtime you can inspect values and ask about their types.
On the other hand, if we are talking about 'L' itself (not about its content, but about the symbol 'L'), it is an atom, because it is not a cons.
Here you are looking at the types of the values that make up the syntax of your code, how it is being represented before even being evaluated (or compiled). You are manipulating a tree of symbols, one of them being L. In the source code, this is a symbol. It has no meaning by itself other than being a name.
Code is data
Lisp makes it easy to represent source code using values in the language itself, and easy to manipulate fragments of code at one point to build code that is executed later. This is often called homoiconicity, thought it is somewhat a touchy word because people don't always think the definition is precise enough to be useful. Another saying is "code is data", something that most language designers and programmers will agree to be true.
Lisp code can be built at runtime as follows (> is the prompt of the REPL, what follows is the result of evaluation):
> (list 'defun 'foo (list 'l) (list 'car 'l))
(DEFUN FOO (L) (CAR L))
The resulting form happens to be valid Common Lisp code, not just a generic list of values. If you evaluate it with (eval *), you will define a function named FOO that takes the first element of some list L.
NB. In Common Lisp the asterisk * is bound in the REPL to the last value being successfully returned.
Usually you don't build code like that, the Lisp reader turns a stream of characters into such a tree. For example:
> (read-from-string "(defun foo (l) (car l))")
(DEFUN FOO (L) (CAR L))
But the reader is called also implicitly in the REPL (that's the R in the acronym).
In such a tree of symbols, L is a symbol.
Evaluation model
When you call function FOO after it has been defined, you are evaluating the body of FOO in a context where L is bound to some value. And the rule for evaluating a symbol is to lookup the value it is bound to, and return that. This is the semantics of the code, which the runtime implements for you.
If you are using a simple interpreter, maybe the symbol L is present somewhere at runtime and its binding is looked up. Usually the code is not interpreted like that, it is possible to analyze it and transform it in an efficient way, during compilation. The result of compilation probably does not manipulate symbols anymore here, it just manipulates CPU registers and memory.
In all cases, asking for the type of L at this point is by definition of the semantics just asking the type for whatever value is bound to L in the context it appears.
An atom is anything that is not a cons cell
Really, the definition of atom is no more complex than that. A value in the language that is not a cons-cell is called an atom. This encompasses numbers, strings, everything.
Sometimes you evaluate a tree of symbols that happens to be code, but then the same rule applies.
Simple expressions
P.S. I'm asking this question due to LISP course at my university, where we have a definition of 'simple expression' - it is an expression, which is atom or function call of one or two atomic parameters. Therefore I wonder if expression (cddddr L) is simple, which depends on whether 'L' is atomic parameter or not.
In that course you are writing functions that analyze code. You are given a Lisp value and must decide if it is a simple expression or not.
You are not interested in any particular interpretation of the value being given, at no point you are going to traverse the value, see a a symbol and try to resolve it to a value: you are checking if the syntax is a valid simple expression or not.
Note also that the definitions in your course might be a bit different than the one from any particular exising flavor (this is not necessarily Common Lisp, or Scheme, but a toy LISP dialect). Follow in priority the definitions from your course.
Imagine we have a predicate which tells us if an object is not a number:
(not-number-p 3) -> NIL
(not-number-p "string") -> T
(let ((foo "another string))
(not-number-p foo)) -> T
(not-number '(1 2 3)) -> T
(not-number (first '(1 2 3)) -> NIL
We can define that as:
(defun not-number-p (object)
(not (numberp object))
Above is just the opposite of NUMBERP.
NUMBERP -> T if object is a number
NOT-NUMBER-P -> NIL if object is a number
Now imagine we have a predicate NOT-CONS-P, which tells us if an object is not a CONS cell.
(not-cons-p '(1 . 2)) -> NIL
(let ((c '(1 . 2)))
(not-cons-p c)) -> NIL
(not-cons-p 3) -> T
(let ((n 4))
(not-cons-p n)) -> T
(not-cons-p NIL) -> T
(not-cons-p 'NIL) -> T
(not-cons-p 'a-symbol) -> T
(not-cons-p #\space) -> T
The function NOT-CONS-P can be defined as:
(defun not-cons-p (object)
(if (consp object)
NIL
T))
Or shorter:
(defun not-cons-p (object)
(not (consp object))
The function NOT-CONS-P is traditionally called ATOM in Lisp.
In Common Lisp every object which is not a cons cell is called an atom. The function ATOM is a predicate.
See the Common Lisp HyperSpec: Function Atom
Your question:
(cadr (caddar (cddddr L)))
Is 'L' an atom?
How would we know that? L is a variable. What is the value of L?
(let ((L 10))
(atom L)) -> T
(let ((L (cons 1 2)))
(atom L) -> NIL
(atom l) answers this question:
-> is the value of L an atom
(atom l) does not answer this question:
-> is L an atom? L is a variable and in a function call the value of L is passed to the function ATOM.
If you want to ask if the symbol L is an atom, then you need to quote the symbol:
(atom 'L) -> T
(atom (quote L)) -> T
symbols are atoms. Actually everything is an atom, with the exception of cons cells.

Elisp: How to push-back to a list

Is there a way to push-back to a list in elisp?
The closest thing I found was
(add-to-list 'myList myValue t) ;; t tells it to put to back of the list
The problem, however, is that add-to-list enforces uniqueness. The other alternative is (push 'myList myVal) but that can only push to the front of a list. I tried using (cons myList myVal) but IIRC that returns something other than a list.
The only thing that has worked is
(setq myList (append myList (list myVal)))
but that syntax is hideous and feels like a lot of extra work to do something simple.
Is there a faster way to push to the back of a list. It's clearly possible as seen in (add-to-list), but is there a way to do it without enforcing uniqueness?
In other words, a good old push-back function like with C++ and the <List> class
Lisp lists vs "lists" in other languages
Lisp lists are chains of cons cells ("linked lists"), not specialized sequential containers like in C, and not a weird blend of lists and vectors like in Perl and Python.
This beautiful approach allows the same methodology to be applied to code and data, creating a programmable programming language.
The reasons Lisp does not have a "push-back" function are that
it does not need it :-)
it is not very well defined
No need
Adding to the end is linear in the length of the list, so, for
accumulation, the standard pattern is to combine
push while iterating and
nreverse when done.
Not well defined
There is a reason why add-to-list takes a symbol as the argument (which makes it useless for programming).
What happens when you are adding to an empty list?
You need to modify the place where the list is stored.
What happens when the list shares structure with another object?
If you use
(setq my-list (nconc my-list (list new-value)))
all the other objects are modified too.
If you write, like you suggested,
(setq my-list (append my-list (list new-value)))
you will be allocating (length my-list) cells on each addition.
Try this:
(defun prueba ()
(interactive)
(let ((mylist '(1 2 3)))
(message "mylist -> %s" mylist)
(add-to-list 'mylist 1 t)
(message "mylist -> %s" mylist)
(setq mylist '(1 2 3))
(add-to-list 'mylist 1 t '(lambda (a1 a2) nil))
(message "mylist -> %s" mylist)
))
adding a compare function that always returns nil as the fourth argument to add-to-list allows you
to add duplicates.

IF error in LISP

I am relatively new to Lisp and I was trying to do a linear search on LISP. But I haven't been able to do so. I am always getting an error that says that "IF has too few parameters".
(setq a '(8 6 2 3 9 5 1))
(LET (key))
(setq key (read))
(loop
(if(= (first a) (key)))
(return t)
(return NIL)
(setq a (rest a))
)
Many problems in your code:
Globally setq an undefined variable
(let (key)) alone does nothing. If you want to define a global variable, use defparameter or defvar.
You if has only a test, and no branches. The special operator if takes a condition, a then expression and an optional else expression: (if test then [else])
If you intended to have your return inside the if, your linear search would stop at the first comparison, because of (return NIL). Indeed, what you would have written would be equivalent to (return (= (first a) key)) and the loop would not even be needed in that case. Maybe you intended to use return to return a value from the if, but if is an expression an already evaluates as a value. return exits the loop (there is an implicit (block NIL ...) around the loop).
(setq a (rest a)) is like (pop a) and would indeed be the right thing to do if you did not already returned from loop at this point.
Just to be sure, be aware that = is for comparing numbers.
The beginning of your code can be written as:
(let ((a '(8 6 2 3 9 5 1))
(key (read)))
(linear-search key a)
Then, how you perform linear-search depends on what you want to learn. There are built-in for this (find, member). You can also use some with a predicate. Loop has a thereis clause. You can even try with reduce or map with a return-from. If you want to learn do or tagbody, you will have an occasion to use (pop a).

Elisp: How to delete an element from an association list with string key

Now this works just fine:
(setq al '((a . "1") (b . "2")))
(assq-delete-all 'a al)
But I'm using strings as keys in my app:
(setq al '(("a" . "foo") ("b" . "bar")))
And this fails to do anything:
(assq-delete-all "a" al)
I think that's because the string object instance is different (?)
So how should I delete an element with a string key from an association list? Or should I give up and use symbols as keys instead, and convert them to strings when needed?
If you know there can only be a single matching entry in your list, you can also use the following form:
(setq al (delq (assoc <string> al) al)
Notice that the setq (which was missing from your sample code) is very important for `delete' operations on lists, otherwise the operation fails when the deleted element happens to be the first on the list.
The q in assq traditionally means eq equality is used for the objects.
In other words, assq is an eq flavored assoc.
Strings don't follow eq equality. Two strings which are equivalent character sequences might not be eq. The assoc in Emacs Lisp uses equal equality which works with strings.
So what you need here is an assoc-delete-all for your equal-based association list, but that function doesn't exist.
All I can find when I search for assoc-delete-all is this mailing list thread:
http://lists.gnu.org/archive/html/emacs-devel/2005-07/msg00169.html
Roll your own. It's fairly trivial: you march down the list, and collect all those entries into a new list whose car does not match the given key under equal.
One useful thing to look at might be the Common Lisp compatibility library. http://www.gnu.org/software/emacs/manual/html_node/cl/index.html
There are some useful functions there, like remove*, with which you can delete from a list with a custom predicate function for testing the elements. With that you can do something like this:
;; remove "a" from al, using equal as the test, applied to the car of each element
(setq al (remove* "a" al :test 'equal :key 'car))
The destructive variant is delete*.
Emacs 27+ includes assoc-delete-all which will work for string keys, and can also be used with arbitrary test functions.
(assoc-delete-all KEY ALIST &optional TEST)
Delete from ALIST all elements whose car is KEY.
Compare keys with TEST. Defaults to ‘equal’.
Return the modified alist.
Elements of ALIST that are not conses are ignored.
e.g.:
(setf ALIST (assoc-delete-all KEY ALIST))
In earlier versions of Emacs, cl-delete provides an alternative:
(setf ALIST (cl-delete KEY ALIST :key #'car :test #'equal))
Which equivalently says to delete items from ALIST where the car of the list item is equal to KEY.
n.b. The answer by Kaz mentions this latter option already, but using the older (require 'cl) names of delete* and remove*, whereas you would now (for supporting Emacs 24+) use cl-delete or cl-remove (which are auto-loaded).
If using emacs 25 or newer you can use alist-get
(setf (alist-get "a" al t t 'equal) t)

How do I apply "or" to a list in elisp

In elisp I can evaluate or as a function just like +.
(or nil 0 nil) ==> 0
(+ 1 0 1) ==> 2
I can use apply to apply + to a list
(apply '+ '(1 0 1)) ==> 2
So, I would think or would work the same way, but it doesn't.
(apply 'or '(nil 0 nil)) ==> error: (invalid-function or)
I imagine this comes from some internal magic used to implement the short-circuit evaluation. How can I use apply to execute the or operation over a list?
P.S. my desired application is to find out whether any elements on the command line match a particular pattern, so the important part of what I am writing is:
(apply 'or (mapcar (lambda (x) (string-match-p "pattern" x)) command-line-args))
But it doesn't work
The problem is that or is a macro (which is the "internal magic" in question), and you're right that that's done so it can do short-circuiting. If or was a function, then calling it would need to follow the usual rules for evaluating a function call: all the arguments would need to get evaluated before the call is made.
See also this question -- it's about Scheme but it's the exact same issue.
As for a solution, you should probably use some, as in:
(some (lambda (x) (string-match-p "pattern" x)) command-line-args)
Note: this uses common lisp that is not included in emacs by default. Just use (require 'cl)
If it makes you feel any better, you're in good company! This is the third question in the "Common Pitfalls" section of the Lisp FAQ:
Here's the simple, but not necessarily satisfying, answer: AND and OR are
macros, not functions; APPLY and FUNCALL can only be used to invoke
functions, not macros and special operators.
...and Eli is of course right on the money with his suggestion to use SOME:
The Common Lisp functions EVERY and SOME can be used to get the
functionality you intend when trying to apply #'AND and #'OR.
(The FAQ and this answer are mostly about Common Lisp but in this case if you omit the # character the answer is the same.)
If you don't care performance, use (eval (cons 'or '(nil 0 nil)))
When I was trying to 'apply' a macro to an argument list, I got an error that the function is unbound, which means that, 'apply' only receives a function, instead of a macro, as its first argument.
In order to fix this, I wrote a new function 'apply-macro' as follows:
(defun apply-macro (macro arg-list)
(eval
`(,macro ,#(loop for arg in arg-list
collect `(quote ,arg)))))
For instance, I wrote a macro to concatenate multiple lists together:
(defmacro conc-lists (&rest lists)
`(funcall #'concatenate 'list ,#lists))
e.g.
(conc-lists '(a b) '(c d) '(e f)) ;;=> (A B C D E F)
Now try 'apply-macro':
(apply-macro 'conc-lists '((a b) (c d) (e f)))
It works and returns the same output.
In fact, it will be expanded into:
(eval
(conc-lists (quote (a b)) (quote (c d)) (quote (e f))))
You can also pass a form to a macro:
(apply-macro 'conc-lists (maplist #'list '(a b c)))
;;=> ((A B C) (B C) (C))
Get back to your question, it's solved:
(apply-macro 'or '(nil 0 nil)) ;;=> 0
I'm only guessing here, but I think or might be one of these 20-odd 'functions' in lisp that are not really functions, since they don't always evaluate all parameters.
This makes sense to make or one of these, since if you have found one TRUE, you can stop searching. In other words, or is not a function as a form of optimization. Still only guessing though.
Eli Barzilay's answer is correct and idiomatic. I want to provide an alternative answer based on dash.el, the library I use to write terse functional-style code, when I have to work with lists. or returns the first non-nil element, nil otherwise, due to short-circuiting. Therefore simply use -first:
(-first 'identity '(nil 0 1 nil)) ; 0
(-first 'identity '(nil nil)) ; nil
identity function simply returns its argument. Which is clever, because -first applies a predicate until it returns non-nil. identity returns non-nil if the argument is itself non-nil. If you simply want to test whether there is non-nil elements in a list, use -any? instead:
(-any? 'identity '(nil 0 1 nil)) ; t
(-any? 'identity '(nil nil)) ; nil