请问 letrec
和 let
的区别是什么?不太了解 common lisp,这个话题搜到的结果大多数和 elisp 没有关系。
看代码注释说只在 lexical-binding 下有作用,不太明白这个到底是用来做什么的。
请问 letrec
和 let
的区别是什么?不太了解 common lisp,这个话题搜到的结果大多数和 elisp 没有关系。
看代码注释说只在 lexical-binding 下有作用,不太明白这个到底是用来做什么的。
NEWS.24
有提到:
New macro
letrec
to define recursive local functions.
比如:
(setq lexical-binding t)
=> t
(letrec ((len (lambda (l)
"Return the length of list L."
(if (null l)
0
(1+ (funcall len (cdr l)))))))
(list
(funcall len '())
(funcall len '(1))
(funcall len '(1 2 3))))
=> (0 1 3)
原来 rec
是 recursive
,学习了
http://www.schemers.org/Documents/Standards/R5RS/HTML/r5rs-Z-H-7.html#%_idx_132
Semantics: The s are bound to fresh locations holding undefined values, the s are evaluated in the resulting environment (in some unspecified order), each is assigned to the result of the corresponding , the is evaluated in the resulting environment, and the value(s) of the last expression in is(are) returned. Each binding of a has the entire letrec expression as its region, making it possible to define mutually recursive procedures.
这段引用里面的<...>
都被md吃掉了,点进去看吧。
这段说明和 emacs 中 letrec
的函数文档比较接近,之前看不太明白。现在稍微明白了点。
貌似 let
的变体不下几十种,这是函数式编程语言的特点吗?
letrec
其实是 Scheme 风格的东西,Common Lisp 因为函数和变量命名空间不一样,用的是 let
和 flet
(不可做递归引用),以及 let*
labels
(可以使用递归),还有 macrolet
, letf
letf*
(作用和 setf
类似)。
Emacs Lisp 本身也可以模拟 Scheme
写 elisp 包的时候发现 letrec
真是相当的好用啊
用 cl-labels
可以少写 lambda 和 funcall 啊
;###autoload
(defmacro exclamation (&rest structure)
"Expand the $ structure as inline macros at compiling time
to optimze byte-code."
(cl-labels ((process
(s)
(if (listp s)
(cl-loop for i in s
collect
(if (and
(listp i)
(eq
(car i)
exclamation-macro-mark))
(let* ((lst (cdr i))
(war (check lst)))
(if war lst
(eval lst)))
(process i)))
s))
(check
(sexp)
;; A example of using `catch' and `throw'.
(catch 'unbound
(cl-loop for x in sexp do ; do form in `loop' always returns nil.
(if (listp x)
(let ((head (car x)))
(unless (fboundp head)
(throw 'unbound t)
(warn
"symbol's function definition void: `%S' "
(car x)))
(unless (or
(macrop head)
(special-form-p head))
check x))
(or
(not (symbolp x))
(boundp x)
(fboundp x)
(progn
(throw 'unbound t)
(warn
"symbol's definition void: `%S'"
x))))))))
(cons 'progn (process structure))))
但是这种情况下不如 letrec
好记, ,看到 let
开头就知道它的大概用法应该是怎样的,因为基本上包含 let
的都和 binding 有关。
你要是不说我绝对想不到 cl-labels
是干吗的。谢谢了,又学到了。
label
其实是 Lisp 7 个原始操作符 2 个记号中 2 个记号之一(另外一个就是 lambda
)
label
具体定义以及其他 7 个操作符的具体介绍可以参照这篇文章:
http://daiyuwen.freeshell.org/gb/rol/roots_of_lisp.html#tex2html3
简单来说 (defun func (args ...) body)
等价于 (label func (lambda (args ...) body))
这样一来为什么定义多个临时函数的特殊形式叫 labels
就好理解了了。
另外在现代的 Lisp 实现中 label
已经消失了。Emacs Lisp 用 C 实现了 defalias
,然后用 defalias
定义了 defmacro
,用 defmacro
定义了 defun
。而早期 Lisp 是没有宏的。其他 Lisp 也用各自的方法定义 defun