LET
block 嵌套在 FLET
/LABELS
block 中是惯用的还是非惯用的?
同样,我可能完全错了,但我正在尝试模仿 Haskell 中的通用 where
block (所以我有一个 defun
并且我想要编写对值和函数使用某些临时绑定(bind)的代码。
如果这些不是惯用语(毕竟,我不应该期望将用法从一种语言转移到另一种语言),那么正确的方法是什么?
例如类似的东西(下面是愚蠢的例子......)
(defun f (x) (
(let* ((x 4)
(y (1+ x))
(flet ((g (x) (+ 2 x)))
(g y))))
最佳答案
您想知道这是否是偏好差异:
(defun f (x)
(let* ((x 4) (y (1+ x)))
(flet ((g (x) (+ 2 x)))
(g y))))
和
(defun f (x)
(flet ((g (x) (+ 2 x)))
(let* ((x 4) (y (1+ x)))
(g y))))
?
flet
/labels
和 let
/let*
的顺序并不重要这个案例。它会产生相同的结果,并且您的 CL 实现可能会优化您的代码,这样结果无论如何都会相同。
在 LISP-1 中,你会把它放在同一个 let
中,然后问题就是你应该把 lambda 放在最前面还是最后。对我来说有点味道。
唯一不同的情况是当您在函数中进行自由变量的计算时。像这样:
(defun f (x)
(let ((y (1+ x)))
(flet ((g (x) (+ 2 x y))) ; y is free, made in the let*
(g x))))
(f 5) ; ==> 13
现在如果不移动逻辑就不可能切换顺序,因为该函数使用自由变量。您可以将 let
放在 g
的定义中,如下所示:
(defun f (x)
(flet ((g (z) ; renamed to not shadow original x
(let* ((y (1+ x)))
(+ 2 z y)))
(g x))))
但假设您将它与 mapcar
、reduce
或递归一起使用。然后它会为每次迭代完成计算,而不是在调用之前计算一次。这些是真正重要的案例。
关于LET block 内的嵌套 FLET block (反之亦然),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23601988/