在ruby中对一个序列处理,大部分是函数式写法。连续串接多个序列处理,写起来也特别的便捷。给开发者的感觉,ruby提倡序列的处理用函数式写法来完成。
而在lisp中,有do,dotimes,dolist, for,while还有cl-loop 这些迭代式写法,也有mapcar这种函数式的写法,我就迷惑了。
迭代式写法
(dolist (c '("a" "e" "k" "u"))
(let ((key (kbd (concat "C-" c))))
(evil-define-key 'insert vterm-mode-map key
`(lambda () (interactive) (vterm-send-string ,key)))))
函数式写法
(mapcar (lambda (c)
(let ((key (kbd (concat "C-" c))))
(evil-define-key 'insert vterm-mode-map key
`(lambda () (interactive) (vterm-send-string ,key)))))
'("a" "e" "k" "u"))
lisp到底推荐那种,什么情况下用哪种比较好?
1 个赞
(dolist (key '([f1] [f2] [f3] [f4] [f5] [f6] [f7] [f8] [f9] [f10] [f11] [f12]))
(define-key vterm-mode-map `,key nil))
这个写法,我想改成(dotimes (n 12) body)
的写法,没有成功,能帮改一下吗?不是洁癖的问题,而是为了练习迭代和`
这个宏
基于(define-key vterm-mode-map [f1] nil))
是正确的写法,改修如下,但不对
(dotimes (n 12)
(let ((key (kbd (concat "f" (int-to-string (1+ n))))))
(define-key vterm-mode-map [`,key] nil)))
[]
代表数组,那么f1,f2…f12就应该是某个变量呀,C-h v却找不到它们。
那么 (define-key vterm-mode-map [f1] nil))
为什么又是正确的呢?
cireu
2019 年2 月 1 日 04:05
5
因为vector字面量具有self-quoting效果
(equal '[3 a] [3 a]) ;; => t
(equal [a b c] (vector 'a 'b 'c)) ;; => t
;; 不能用`eq',因为eq比较两个symbol的内存地址是否一致。
[f1]
里面装的也不是字符串,是symbol。要把string转化为symbol可以用intern
string都会有双引号包裹的
(equal [f1] (vector (intern "f1"))) ;; => t
1 个赞
好的,明白了,还有self-quoting这个概念,学习了。已收藏。
eq和equal的区别,这个我清楚。
intern这个函数,我倒是知道,因为前面不知道有self-quoting的概念,所以也没联系起来。
另外扩展一下,常用的有self-quoting功能的是哪些?
受教了!谢谢!
勉強なりました!ありがとうございます!
cireu
2019 年2 月 1 日 04:19
7
guodongsoft:
常用的有self-quoting功能的是哪些?
(equal "Emacs" '"Emacs")
(equal 3 '3)
(equal :keyword ':keyword)
(equal ?a '?a)
均为t
1 个赞
guodongsoft:
常用的有self-quoting功能的是哪些
除了 list 和 symbol 其它所有元素都是 self quoting
cireu
2019 年2 月 1 日 04:32
9
keyword 算constant symbol的
我并没有说 keyword 就不会 self quote 了,除此以外还有 t 和 nil,或者其实可以理解为,keyword 只是 intern 的时候自动把值设为本身,并不算 self quoting,因为对于 string, number 来说 symbol-value 并没有作用。
我理解的还是不到位
(dolist (key '([f1] [f2] [f3] [f4] [f5] [f6] [f7] [f8] [f9] [f10] [f11] [f12]))
(define-key vterm-mode-map `,key nil))
改成下面的写法也不对
(dotimes (n 12)
(let ((key (intern (concat "f" (int-to-string (1+ n))))))
(define-key vterm-mode-map [`,key] nil)))
[`,key]
,[]是self-quoting的,在这里`,key
返回的也是个quote,所以失败。但我又不清楚怎么改成正确的。
You know why? Do you even think this would work?
(let ((a 12)) `"b,a") ;; => "b12"
dotimes
dolist
cl-loop
都是宏,都是用 while
实现的,编译过后它们之间常常没差别,本质上跟你直接用 while
一样。dolist
更多时候跟 mapc
相互替换,都是仅为了副作用。
开启 lexical-binding
的话,用不着执行里面的 key
,lexical 环境下执行 lambda
会生成 closure
(可以存储环境变量的 lambda
):
(car
(mapcar (lambda (c)
(let ((key (kbd (concat "C-" c))))
(lambda () (message "=> %S" key))))
'("a" "e" "k" "u")))
;; => (closure ((key . "^A") (c . "a") t) nil (message "=> %S" key))
我说怎么没scheme方便呢?原来没开启词法作用域。过会儿我试一下
cireu
2019 年2 月 1 日 05:17
15
因为[]
已经阻断了Emacs对`
reader macro的解析。你应该用`[,key]
楼主的这些疑问,找一本lisp入门书过一遍效果会比较好,推荐 A gentle introduction to symbolic computation 和practical Common Lisp 的前几章
好的,书也在看,不过最近才开始,所以会遇到还没看到的知识点。
现在看的是ANSI Common Lisp,但内容不是很多,很多东西和scheme接近。先看完这个再说
cireu
2019 年2 月 1 日 05:32
19
guodongsoft:
连续串接多个序列处理
你可能会喜欢
(mapc (lambda (x)
(--> x
(concat "C-" it)
(kbd it)
(evil-define-key 'insert vterm-mode-map it
(lambda () (interactive)
(vterm-send-string it)))))
'("a" "e" "k" "u"))
(defmacro --> (x &rest forms)
"Starting with the value of X, thread each expression through FORMS.
Insert X at the position signified by the symbol `it' in the first
form. If there are more forms, insert the first form at the position
signified by `it' in in second form, etc."
(declare (debug (form body)))
`(-as-> ,x it ,@forms))
(defmacro -as-> (value variable &rest forms)
"Starting with VALUE, thread VARIABLE through FORMS.
In the first form, bind VARIABLE to VALUE. In the second form, bind
VARIABLE to the result of the first form, and so forth."
(declare (debug (form symbolp body)))
(if (null forms)
`,value
`(let ((,variable ,value))
(-as-> ,(if (symbolp (car forms))
(list (car forms) variable)
(car forms))
,variable
,@(cdr forms)))))
From dash.el
1 个赞
挪一下`
的位置,就OK了。
(dotimes (n 12)
(let ((key (intern (concat "f" (int-to-string (1+ n))))))
(define-key vterm-mode-map `[,key] nil)))
这个写法太赞了,你的例子在最后一句,我小改了一下
(mapc (lambda (x)
(--> x
(concat "C-" it)
(kbd it)
(evil-define-key 'insert vterm-mode-map it
`(lambda () (interactive) (vterm-send-string ,it)))))
'("a" "e" "k" "u"))
这个和ruby的思路接近,但过程不一样
ruby是前一个序列处理结束之后,把结果传递给下一个序列处理,每个步骤的结果都是一个序列。
这里是先利用–>宏是把每个元素串接处理,再利用mapc把结果形成一个序列。
但ruby的方法,也有其灵活性,比如 listobj.map(…).filter (…).map(…),也就是,ruby的方式在串接处理的时候,可以改变序列的长度。
而–>宏就做不到了,需要在mapc外层加filter了。总之,我还是比较喜欢–>这个宏。