使用“(list ...)”和直接手写list哪种更好?


#1

我强迫症又犯了……

1

(defvar remx-lisp-modes (list 'emacs-lisp-mode 'lisp-mode 'clojure-mode))

2

(defvar remx-lisp-modes '(emacs-lisp-mode lisp-mode clojure-mode))

这两种哪种好一点?以及什么时候该用list函数,什么时候又该手写list?


计算函数被执行过的次数
#2

需要求值就 (list ...),无需求值就 '(...)


#3

个人习惯为主吧…


#4

'(1 2 3) 是个常量,正如数字 100 也是常量,不同的是 Emacs 实际上允许你修改前者。(list 1 2 3) 不是常量,所以对它进行修改合情合理。如果一个局部变量的值为常量,修改这个常量会产生令人意外的结果:

(defun foo ()
  (let ((l '(1 2 3)))
    (cl-incf (car l))
    l))

(defun bar ()
  (let ((l (list 1 2 3)))
    (cl-incf (car l))
    l))

(foo)
;; => (2 2 3)
(foo)
;; => (3 2 3)
(foo)
;; => (4 2 3)

(bar)
;; => (2 2 3)
(bar)
;; => (2 2 3)
(bar)
;; => (2 2 3)

除了全局变量,其它地方的常量如果有可能会被修改,应该使用 (list 1 2 3) 而不是 '(1 2 3),如下面第二种写法是正确的:

(defun my-favourite-numbers ()
  '(1 2 3))

(defun my-favourite-numbers ()
  (list 1 2 3))

#6

如果这个list确实不可能被修改,那么吹毛求疵地讲,哪种好点?

谢谢


#7

理论上list最好,随心所欲,当然,如果你的list里所有东西都要quoted,list会比较累。

举例:emacs内置宏都是cons和list写的,而不是什么backquote和comma comma-at


#8

可以用 byte-compile 看看byte-code

位置2是用到的常量 会被字节码030x用到

不只是’() 还有[] 凡是可以用aset设置的应该都会这样(还不知道能不能append)

你甚至都不能使用字符串


#9
(defun zz ()
  (let ((zz "ABC"))
    (aset zz 0 (+ 1 (aref zz 0)))
    zz))

#10

我还能用字符串吗?

还是我得写成 (list ?H ?e ?l ?l ?o)


#11

String 从属于 Array,其内容可变,"ABC"'(1 2 3) 以及 [1 2 3] 都是「常量」,最好不要修改它们,除非你理解究竟怎么回事,而如果要修改它们,你的表达是

(string ?A ?B ?C)
(list 1 2 3)
(vector 1 2 3)

或者用 copy-sequence 生成(浅)拷贝

(defun zz ()
  (let ((s (copy-sequence "ABC")))
    (cl-incf (elt s 0))
    s))

(zz)
;; => "BBC"
(zz)
;; => "BBC"

#12

我发了 三 个


#13

第一个函数看上去是修改了常量1的值?之后在哪里使用1都会变成4?但是我试了一下似乎不是这样


#14

他只是改变了 '(1 2 3) 中的第一个的值

1 怎么可能改变呢!


#15

@xuchunyang 所说,原地修改 let 声明的列表元素确实存在问题:

#+BEGIN_SRC emacs-lisp :results output
(defun foo ()
  (let* ((l '(1 2 3)))
    (dotimes (i (length l))
      (setf (nth i l) (1+ (nth i l))))
    (print l)))
(foo)
(foo)
(foo)
#+END_SRC

#+RESULTS:
: 
: (2 3 4)
: 
: (3 4 5)
: 
: (4 5 6)

但是我们不是应该采用更加安全无副作用的方式得到新的列表吗:

#+BEGIN_SRC emacs-lisp :results output
(defun foo ()
  (let ((l '(1 2 3)))
    (print (mapcar (lambda (e) (1+ e)) l))))
(foo)
(foo)
(foo)
#+END_SRC

#+RESULTS:
: 
: (2 3 4)
: 
: (2 3 4)
: 
: (2 3 4)

所以我认为,大多数时侯考量的重点仍然是“是/否需要求值”:

'(foo bar)
;; => (foo bar)

(list 'foo (if CONDITION 'bar 'qux))
;; => (foo bar) or (foo qux)