add-hook和lambda ?

哪裡有得看?

另外一个东西大家要注意的是: lisp 里面描述的许多东西,都是表面上看不到的,而是内存里面的东西,比如: lisp 说函数, 一般是指 函数对象,而我们经常讲的函数,是函数定义,是lisp文本, 函数的定义 eval 之后才是函数对象呢。

从 common lisp 的教材里面看是最简单的, 多翻基本书,比较的看最好。

我并沒有看到具体哪本 Common Lisp 有讲 eval 实現的。

不是 eval 实现, 是 lisp 执行规则。。。。

回过头來,我并未发現 (funcall (function ...)) 的定义有何不妥。

First get form’s function def, then call the function.

我有时候会懒惰写成这样

  (define-key evil-motion-state-map (kbd "C-j")
    (defun my-xref/find-definitions ()
      (interactive)
      (if lsp-mode (lsp-ui-peek-find-definitions) (spacemacs/jump-to-definition))))

调用lsp-modexref-find-definition 弹出来的:

Visit tags table(default TAGS): my-dir

这是要配置什么东西么,我看lsp-mode 的demo 的时候,都是直接跳转的。最近想用 lsp-mode, 想了解这个

我越看越看不明白了……

楼主啊,你前两天还在知乎上赞了这篇用java写一个lisp解释器,里面有Paul Graham的roots of lisp的中译版,里面讲了如何自举lisp,包括怎么在已有lambda时定义出defun(文章里叫label,他讲的大概是上面大家说的lisp-2)。你如果看了的话,这个帖子的问题应该不难理解(虽然讨论里带到的东西我还有不少疑惑吧)


defun的文档说The return value is undefined.?

这个帖子已经爆炸了,无关内容快去另开帖

哎……我的lisp水平就是三脚猫而已……

而且我始终有点拿其他语言往上套的思想,所以就提了这么个愚蠢的问题……

和 Root of Lisp 沒关系。那是最早期的 Lisp,Emacs Lisp 的设计己经变了很多。label 更是早就废弃了。另外 Root of Lisp 里面实現的是 Lisp-1.

然而大多數時候都能起作用。

FWIW,关于 defun 的返回值的变化,Emacs 24.3 的 NEWS 有提及:

3 个赞

我不觉得,用已经有的知识去理解未知的信息是人学习的基本方式,产生混乱是明白的开端,你这个帖子开的好,比那种字体对齐,org导出中文pdf之类的月经贴要有意思的多,也有价值的多

2 个赞

不建议这么写,看起来很怪异。。。。

另外,let over lambda 宏之前的章节建议看一看。。。

还有onlisp宏之前的章节

On Lisp 的精隨其實在后面的 Continuation.

你一下回复这么多,论坛没有提示你

如果要一次回复多个人,试试在一次回复中不断引用他们的回复

:thinking:

楼上诸位展开太深了。

如果只是回答:

很简单,一个字:懒

懒惰的写法:

(add-hook 'xxx-mode-hook
          (lambda ()
            ...))

不厌其烦的写法:

(defun foo (lambda ()
            ...))

(add-hook 'xxx-mode-hook 'foo)

楼主后面又问了,为什么 add-hook 第二参数必须是 FUNCTION,不能是 S 表达式。答案也很简单:因为 add 之后,将由 (funcall FUNCTION) 来执行传进来的函数,如果不是函数就会出错。而参数列表本身不具备约束力,传什么都可以。

接下来就是函数名的问题了。函数执行之前,首先要对其参数进行求值,所以如果直接写:

(add-hook 'xxx-mode-hook foo)

那么 foo 就会被当作变量处理了,可以通过 M-x ielm 来观察这一求值过程:

ELISP> (defun foo () (message "foo"))
foo
ELISP> foo
*** Eval error ***  Symbol’s value as variable is void: foo
ELISP> 'foo
foo

ELISP> (defvar bar "bar")
bar
ELISP> bar
"bar"
ELISP> 'bar
bar

所以写成 'foo 确保传进去的是 SYMBOL:

(add-hook 'xxx-mode-hook 'foo)
;; 等效
;; (add-hook (quote xxx-mode-hook) (quote foo))

虽然传递函数名和 lambda 执行效果没什么区别,但还是有些需要注意的,例如:

(add-hook 'xxx-mode-hook 'foo) 之后,xxx-mode-hook 的内容是

(foo ;; <-- 最近添加
 bar
 quux
 ...)

(add-hook 'xxx-mode-hook (lambda () (message "foo"))) 之后,其内容则是

((lambda () (message "foo")) ;; <-- 最近添加
 bar
 quux
 ...)

所以如果是传递的是函数名,将来需要改变函数 foo 的行为,直接修改就可以了。但如果传递的是 (lambda ...),要修改就比较麻烦了,必须整个 (lambda ..) 一字不漏抄一遍:

(remove-hook 'xxx-mode-hook (lambda () (message "foo")))

然后,修改,重新添加:

(add-hook 'xxx-mode-hook (lambda () (message "bar")))

所以说,偷懒是有代价的。

(defun ...)(lambda ...) 的关系,对应到 c 语言,我感觉因类似指针和结构体的关系(毕竟 c 不能把函数当值传递):

(add-hook 'xxx-mode-hook 'foo)           ;; 指针(传引用)
(add-hook 'xxx-mode-hook (lambda ()...)) ;; 结构体(传值,一大拖东西)

实际上,(defun ...) 展开之后也是个 lambda,只不过有了一个别名,例如 foo:

(defun foo ()
  (message "foo"))

;; 展开 =>

(defalias (quote foo)
  (function
   (lambda nil (message "foo"))))
10 个赞