passky
1
这里的行为相当怪异,
let起到了类似labels的作用.
感觉是elisp对let做了什么hack处理.
(defun my-fact (input)
"Return factorial of INPUT."
(let ((my-inside-fact #'(lambda (to-multiply next-gen)
(if (< to-multiply 1)
next-gen
(funcall my-inside-fact (- to-multiply 1) (* next-gen to-multiply))))))
(funcall my-inside-fact (- input 1) input)))
(message "%s" (my-fact 10))
;; => 3628800
这个行为很正常啊,my-inside-fact
是一个变量而不是函数(elisp里函数和变量在不同的空间里),这个变量的值是一个函数(准确地说是一个 lambda closure)。你调用这个变量里的函数的时候也是用的funcall
而不是apply
。你看一下funcall
和apply
的区别就知道了。
没有任何问题,cl的labels定义的是函数(至少cl-labels
是这样),不是变量。你把我之前的回复再读一遍。
LdBeth
5
因为 Emacs Lisp 默认是动态作用域,Common Lisp 是靜态作用域。
在 elisp 里开 (setq lexical-binding t)
就会和 CL 一样报错
Debugger entered--Lisp error: (void-variable my-inside-fact)
(funcall my-inside-fact (- to-multiply 1) (* next-gen to-multiply))
(if (< to-multiply 1) next-gen (funcall my-inside-fact (- to-multiply 1) (* next-gen to-multiply)))
在 CL 里 (defvar my-inside-fact)
以后 (my-fact 10)
能和 elisp 一样不报错运行
CL-USER> (defvar my-inside-fact)
MY-INSIDE-FACT
CL-USER> (defun my-fact (input)
"Return factorial of INPUT."
(let ((my-inside-fact #'(lambda (to-multiply next-gen)
(if (< to-multiply 1)
next-gen
(funcall my-inside-fact (- to-multiply 1) (* next-gen to-multiply))))))
(funcall my-inside-fact (- input 1) input)))
MY-FACT
CL-USER> (my-fact 10)
3628800 (22 bits, #x375F00)
2 个赞
cireu
6
用let定义递归函数得用letrec
或者cl-labels
(defun my-fact (input)
"Return factorial of INPUT."
(letrec ((my-inside-fact
#'(lambda (to-multiply next-gen)
(if (< to-multiply 1)
next-gen
(funcall my-inside-fact (- to-multiply 1) (* next-gen to-multiply))))))
(funcall my-inside-fact (- input 1) input)))
;; Expands to
(defun my-fact (input)
"Return factorial of INPUT."
(let
(my-inside-fact)
(setq my-inside-fact
(function
(lambda
(to-multiply next-gen)
(if
(< to-multiply 1)
next-gen
(funcall my-inside-fact
(- to-multiply 1)
(* next-gen to-multiply))))))
(funcall my-inside-fact
(- input 1)
input)))
2 个赞