`#'`和`'`有什么区别?


'(+ 1 2)
> (+ 1 2)

#'(+ 1 2)
> (+ 1 2)

(defun get-add-n (n)
  ' (lambda (x)
      (+ x n)))
> get-add-n


(defun get-add-n (n)
  #' (lambda (x)
       (+ x n)))
> get-add-n


(defvar get-add-2 ' (lambda (x) (+ x 2)))
> (lambda (x) (+ x 2))

(defvar get-add-2 #' (lambda (x) (+ x 2)))
> (closure (t) (x) (+ x 2))

看起来好像就是defvar的时候有点区别,但还是不明白什么区别

' 表示不求值直接返回, '(lambda (x) (+ x 2)) 这个表达式直接返回了 lambda 列表。

如果使用 (lambda (x) (+ x 2)) 则会返回闭包表达式。lambda 这个宏在内部使用的就是 #' ,也就是 function 这个 special form。

另外,一般没必要在 lambda 表达式前面加 '

硬要在 开lexical的前提下 不用闭包的标准做法 是不是 就是加 quote?

额,大佬,还是没懂 #' 的作用,是去取 symbol 中的 function域的意思吗?

我怀疑你想表达的是 symbol-function 这个函数. 不是.

不处理 lambda 表达式的时候和 ' 一个作用

处理 lambda 表达式的时候在词法作用域开启的情况下会将 lambda 表达式转化成闭包

和 defvar,defun 没有关系

有点明白,能给个相关doc传送门吗?我只找到 quote 的,Quoting (GNU Emacs Lisp Reference Manual)

#‘ 不知道搜什么, hashtag,hash,octothorpe 都试了一遍,没找到相关资料

搜索 emacs #' 应该能找到不少资料,比如: lisp - When should Emacs #'function syntax be used? - Stack Overflow

function (aka #') is used to quote functions, whereas quote (aka ') is used to quote data. Now, in Emacs-Lisp a symbol whose function cell is a function is itself a function, so #'symbol is just the same as 'symbol in practice (tho the intention is different, the first making it clear that one is not just talking about the symbol “symbol” but about the function named “symbol”).

The place where the difference is not just stylistic is when quoting lambdas: '(lambda ...) is an expression which evaluates to a list whose first element is the symbol lambda. You’re allowed to apply things like car and cdr to it, but you should not call it as if it were a function (although in practice it tends to work just fine). On the contrary #'(lambda ...) (which can be written just (lambda ...)) is an expression which evaluates to a function. That means you can’t apply car to it, but the byte-compiler can look inside #'(lambda ...), perform macro-expansion in it, warn you if what it finds doesn’t look kosher, etc…; For lexical-binding it even has to look inside in order to find the free variables to which that function refers.

可以看看 Evolution of Emacs Lisp 的 lambda 相关章节,我这里截取一段:

在 Lisp 方言中,匿名函数一般都是 lambda 表达式的值。下面是一个将数字加一的匿名函数:

(lambda (x) (+ x 1))

有趣的是, lambda 原本在 Emacs Lisp 不是一个关键字(与 MacLisp 不同),但匿名函数的值可以是以下形式的列表:

(lambda (..ARGS..) ..BODY..)

动态作用域的使用导致没有必要创建闭包,所以在源代码中直接使用已有 quote 机制编写匿名函数是可行的:

'(lambda (..ARGS..) ..BODY..)

对这个表达式求值会得到一个嵌套列表结构,它的首元素是符号 lambda 。当某个程序使用这样一个值调用 funcall 时, funcall 会将这个列表结构识别为一个 lambda 表达式并对其调用解释器。

这个额外的 ' 字符是为了让 Lisp 实现更简单的小小代价。但字节码编译器不被允许编译这样的引用列表,除非在极少数情况下它能确定列表只会作为函数使用。因此 Emacs Lisp 在 1.4 版本中添加了 function special form(也是从 MacLisp 导入的)来作为替代表示法:

(function (lambda (..ARGS..) ..BODY..))

在 1992 年,也就是 Emacs 19 的早期开发阶段, lambda 被作为宏加入到 Emacs Lisp 中。这个宏简单地将列表包裹在 function 中并返回:

(defmacro lambda (&rest args) (list 'function (cons 'lambda args)))

对于为什么在引入这个简单的宏上花了这么长的时间还不完全清楚,不过这可能是因为匿名函数并不经常使用,而且它们主要用于对性能要求不是很高的地方。

虽然 lambda 宏使得 (lambda ...) 在近 30 年来优于 '(lambda ...) ,但这种做法仍然可以在许多在网上发布的代码片段、用户配置文件和第三方 Emacs Lisp 包中找到,这主要归功于复制粘贴的便利,尽管它会阻止对函数体进行字节码编译。

有些相关的是,直到 1993 年 Lucid Emacs 19.8 才从 MacLisp 中引入了 '#... 作为 (function ...) 的读取器简写形式。Emacs 则在随后的一年跟进。

5 个赞

不太清楚,似乎没有必要在词法作用域中使用动态作用域,而且 defvar 可以声明动态作用域变量

不需要,这是 Emacs 24 以前的不规范写法遗留。反而是在没 lexical binding 之前会用 backquote 捕捉变量

1 个赞

#'这个东西叫Special Read Syntax