Idiomatic way to destructively add elements to a list? - emacs

Is there a nice way to add elements to a list stored in a variable? The ways I'm using aren't very pretty.
Starting list:
(setq sml/hidden-modes (list " hl-p"))
Add items to sml/hidden-modes:
;; First way I append the items to hidden-modes and set it again
(setq sml/hidden-modes (append sml/hidden-modes
(list " AC" " Undo-Tree" " Smrt")))
;; Second way I use add-to-list to add items one at a time instead of all at once
(mapcar (lambda (mode) (add-to-list 'sml/hidden-modes mode))
(list " AC" " Undo-Tree" " Smrt"))
;; Way I see people doing it in random .emacs snippets I find
(add-to-list 'sml/hidden-modes " AC")
(add-to-list 'sml/hidden-modes " Undo-Tree")
(add-to-list 'sml/hidden-modes " Smrt")

If you know in advance that the original list is non-nil, you can try nconc:
ELISP> (setq a '(1 2 3))
(1 2 3)
ELISP> (nconc a '(4 5 6))
(1 2 3 4 5 6)
ELISP> a
(1 2 3 4 5 6)

dash list library has !cons to prepend elements in-place:
(let ((xs '(2 3))) (!cons 1 xs) xs) ; (1 2 3)
Other than that read GNU Emacs Lisp Reference Manual's section Modifying Existing List Structure.

Related

Elisp use apply on progn for list of functions

I am a new emacs user. And trying to write some Elisp to learn this software better. While I meet some problems.
I want to use apply on progn to run a list of functions in sequence. But I got errors as below. I am just confused and need some help to tell me how to achieve this in Elisp, thanks.
(progn
(+ 1 1)
(+ 2 2)
)
;; => 4
(apply #'progn ((+ 1 1) (+ 2 2)))
;; => Invalid function: (+ 1 1)
(apply #'progn ('(+ 1 1) '(+ 2 2)))
;; => Invalid function: '(+ 1 1)
(apply #'progn '((+ 1 1) (+ 2 2)))
;; => Invalid function: #<subr progn>
I toy play as above cause I come to emacs from vim. So I installed evil and evil number. And want back the vim number inc and dec bindings C-a, C-x. So I write a macro as blow to avoid boilerplate.
(defmacro set-evil-number-keymap (key-set func &rest modes)
`(apply 'progn
,(-map
(lambda (mode)
`(define-key ,(intern (concat "evil-" mode "-state-map")) (kbd ,key-set)
',(intern
(concat "evil-numbers/" func))))
,modes)))
(set-evil-number-keymap "C-a" "inc-at-pt" "normal" "insert")
(set-evil-number-keymap "C-x" "dec-at-pt" "normal" "insert")
My expectation is something below. While it just not run.
(progn
(define-key evil-normal-state-map (kbd "C-a") ’evil-numbers/inc-at-pt) (define-key evil-visual-state-map (kbd "C-a") ’evil-numbers/inc-at-pt))
(progn
(define-key evil-normal-state-map (kbd "C-x") ’evil-numbers/dec-at-pt) (define-key evil-visual-state-map (kbd "C-x") ’evil-numbers/dec-at-pt))
You can't call apply on "special forms" like progn (see info (elisp)Special Forms), which have unique evaluation rules.
progn itself already provides a mechanism for sequenced evaluation, so your initial attempt does do what you want. At the top-level, however, the forms will be executed sequentially anyway, so there is no need for a progn there.
You don't need to use apply in the macro, elisp have ,# to flatten a list to args. So the correct answer is
(defmacro set-evil-number-keymap (key-set func &rest modes)
`(progn
,#(-map
(lambda (mode)
`(define-key ,(intern (concat "evil-" mode "-state-map")) (kbd ,key-set)
',(intern
(concat "evil-numbers/" func))))
,modes)))
Not sure what you're expecting. progn returns value of the last forms, so 4 is excepted, consult C-h f progn:
progn is a special form in `C source code'.
(progn BODY...)
Eval BODY forms sequentially and return value of last one.
If you want to see the result of (+ 1 1), you need to ask for it, for example,
(list (+ 1 1) (+ 2 2))
;; => (2 4)
;; Step 1
(list 2 (+ 2 2))
;; Step 2
(list 2 4)
;; Step 3
(2 4)
The function arguments are evaluated from left to right. By the way, Emacs Lisp doesn't support multiple return value.
(apply #'progn ((+ 1 1) (+ 2 2)))
;; => Invalid function: (+ 1 1)
Since the second argument of the function apply is ((+ 1 1) (+ 2 2)), Emacs needs to calculate its value and to calculate form like (foo 1 2 3), foo has to be a function, but (+ 1 2) is not a function, it's just an ordinary list with 3 elements.
(apply #'progn ('(+ 1 1) '(+ 2 2)))
;; => Invalid function: '(+ 1 1)
'(+ 1 2), that is, (quote (+ 1 2)) isn't a function either, it's a list with two elements.
(apply #'progn '((+ 1 1) (+ 2 2)))
;; => Invalid function: #<subr progn>
progn isn't a function, it's a special form. and, or, let and while are all special forms, they are like macros, they doesn't evaluate arguments eagerly.
(elisp) Calling Functions mentions
special forms and macros do not make sense in `apply'.
You had a bit of an XY problem, but what works for your nominal question is to
(eval (cons 'progn
'((print (+ 1 1))
(print (+ 2 2)))))
eval is generally considered a beginner programmer's misunderstanding, but in this case you just can't use apply for the reasons Rorschach explained. Elisp actually follows the Common Lisp spec here, which says for apply that
it is illegal for the symbol to be the name of a macro or special form
So, in general, you have to use eval directly on the program you've assembled by cons-ing a progn to your "instruction list".

Store list from file input stream, in a variable in LISP

I have lets say the following list in a .txt file
(5 3 1)
All i am trying with following source code is to store the above list in a variable in LISP. Until the first format everything seems right. But then i realize that *originalStateVar* is not getting treated as a list with 3 atoms but as a list with 1 atom. Source code follows:
(defvar *originalStateVar*)
(defun fileInput ()
(let ((i 1)(in (open *originalStateLocation* :if-does-not-exist nil)))
(when in
(loop
for line = (read-line in nil)
while line do
(format t "~a~%" line) ;debug line
(format t "i is <~a>~%" i) ;debug line
(setf *originalStateVar* (list line)) ;storing list in variable
(setf i (+ i 1))) ;debug line
(close in))
(format t "originalStateVar is <~a>" (car *originalStateVar*))
(format t "second element originalStateVar is <~a>~%" (cadr *originalStateVar*))
(format t "third element originalStateVar is <~a>~%" (caddr *originalStateVar*))))
The output of the above code though is:
(5 3 1)
i is <1>
first element originalStateVar is <(5 3 1)>
second element originalStateVar is <NIL>
third element originalStateVar is <NIL>
All i can tell is that it stores the (5 3 1) as a single atom in a list, so it becomes something like ((5 3 1)) and that's why cadr returns NIL.
Any help on how to make *originalStateVar* get treated that way, would be greatly appreciated!
use WITH-OPEN-FILE instead of OPEN
use READ instead of READ-LINE
Example:
CL-USER 11 > (let ((*read-eval* nil))
(with-open-file (in "/tmp/test.data")
(read in)))
(1 2 3)
CL-USER 12 > (let ((*read-eval* nil))
(with-open-file (in "/tmp/test.data")
(describe (read in))))
(1 2 3) is a LIST
0 1
1 2
2 3

What is the role of the # character in Emacs Lisp?

As used for instance in this macro definition:
(defmacro with-eval-after-load-feature (feature &rest body)
(declare (indent 1) (debug t))
(let* ((feature (if (and (listp feature) (eq (car-safe feature) 'quote))
(cdr feature) feature))
(fs (if (listp feature) feature (list feature)))
(form (or (and (eval '(eval-when (compile)
(with-eval-after-load-feature-preload fs)))
'with-no-warnings)
'progn)))
`(,form ,#(with-eval-after-load-feature-transform fs body))))
in this file.
It's used for splicing in backquoted expressions. See C-h i g (elisp) Backquote RET. For example:
elisp> `(1 2 ,(list 3 4)) ; no splicing => nested list
(1 2
(3 4))
elisp> `(1 2 ,#(list 3 4)) ; splicing => flat list
(1 2 3 4)
Asking Emacs is always a sensible approach:
C-hig (elisp) RET
I # RET
This shows you all the elisp manual's index entries for # (one of which is the ,# you were actually looking for).

Should I call add-to-list in Emacs Lisp a destructive function?

add-to-list is often used to add an element to a list if the element is not in the list.
(let* ((aa (list 1 2 3))
(bb aa))
(add-to-list 'aa 0)
(list :aa aa :bb bb))
=> (:aa (0 1 2 3) :bb (1 2 3))
Should one call add-to-front a destructive function because it changes the meaning of name aa? Or should it be called non-destructive because the list that aa used to point to is intact?
(let* ((cc (list 1 2 3))
(dd cc))
(add-to-list 'cc 0 t)
(list :cc cc :dd dd))
=> (:cc (1 2 3 0) :dd (1 2 3))
For Emacs newbies wondering why bb and dd equals (1 2 3), feel free to open a separate stackoverflow question for that and leave a link with "add comment" button. For Emacs newbies wondering why some fellow newbies would wonder that, replace (add-to-list 'aa 0) with (setcar aa 111) and see.
For Lispers who don't use Emacs, here's a simplified definition of add-to-list
(defun simple-add-to-list (list-var element &optional append)
"Add ELEMENT to the value of LIST-VAR if it isn't there yet.
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."
(let ((lst (symbol-value list-var)))
(if (member element lst)
lst
(set list-var
(if append
(append lst (list element))
(cons element lst))))))
If it's capable of modifying the list passed to it, then it's destructive.
If a function takes a list via a symbol, it should be automatically assumed to be destructive, no? Otherwise why not just take the list itself?

How to convert a string to list using clisp?

How can i convert the string "1 2 3 4 5 6 7" into the list (1 2 3 4 5 6 7) elegantly? I am using CLISP.
Here is a recursive solution.
;Turns a string into a stream so it can be read into a list
(defun string-to-list (str)
(if (not (streamp str))
(string-to-list (make-string-input-stream str))
(if (listen str)
(cons (read str) (string-to-list str))
nil)))
You should use parse-integer in a loop.
For example, using loop:
(let ((string "1 2 3"))
(loop :for (integer position) := (multiple-value-list
(parse-integer string
:start (or position 0)
:junk-allowed t))
:while integer
:collect integer))
⇒ (1 2 3)
If you need better control about the splitting, use the split-sequence or cl-ppcre library.
If you need to parse more general number formats, use the parse-number library.
Libraries are available from Quicklisp.
Hint: Take a look at with-input-from-string.
(with-input-from-string (s "1 2 3 4 5 6 7" :index i :start 0 :end 13)
(list (read s) (read s) (read s) (read s) (read s) (read s)))
(1 2 3 4 5 6 7)
it works however i feel it is not so elegant as there are many read call .
thanks again!
I think this might work:
(setf s "1 2 3 4 5 6 7")
(setf L-temp (coerce s 'list))
This makes a list with spaces as elements. Remove spaces:
(setf L-final (remove #\Space L-temp))
I see that Svante is right. My previous attempt did not work. Here is another attempt. I use concatenate to change the string into a list representation. Then I use read-from-string to convert the string (s-2) into an actual list.
(setf s-0 "1 2 3 4 5 6 7")
(setf s-1 (concatenate 'string "(" s ")" ))
(setf s-2 (read-from-string s-1))
I roll it into a function like this:
(defun from-string-to-list (s)
(let ((L (read-from-string
(concatenate 'string "(" s ")"))))
L))
The only purpose of "let" and "L" is to make the function from-string-to-list return only the list and not return multiple values. read-from-string returns two values: The list and the size of the string, I think.
That would do,
(with-input-from-string (s "1 2 3 4 5")
(let ((r nil))
(do ((line (read s nil 'eof)
(read s nil 'eof)))
((eql line 'eof))
(push line r))
(reverse r)))