我强迫症又犯了……
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?
我强迫症又犯了……
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?
需要求值就 (list ...)
,无需求值就 '(...)
。
个人习惯为主吧…
'(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))
如果这个list确实不可能被修改,那么吹毛求疵地讲,哪种好点?
谢谢
理论上list最好,随心所欲,当然,如果你的list里所有东西都要quoted,list会比较累。
举例:emacs内置宏都是cons和list写的,而不是什么backquote和comma comma-at
可以用 byte-compile 看看byte-code
位置2是用到的常量 会被字节码030x用到
不只是’() 还有[] 凡是可以用aset设置的应该都会这样(还不知道能不能append)
你甚至都不能使用字符串
(defun zz ()
(let ((zz "ABC"))
(aset zz 0 (+ 1 (aref zz 0)))
zz))
我还能用字符串吗?
还是我得写成 (list ?H ?e ?l ?l ?o)
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"
我发了 三 个
第一个函数看上去是修改了常量1的值?之后在哪里使用1都会变成4?但是我试了一下似乎不是这样
他只是改变了 '(1 2 3) 中的第一个的值
1 怎么可能改变呢!
如 @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)