将LET
块嵌套在FLET
/ LABELS
块内是否被视为惯用或非惯用?
同样,我可能会出现这种错误,但我试图模仿Haskell中的通用where
块(所以我有defun
并且我想编写使用某些的代码值和函数的临时绑定。
如果这些都是非惯用的(毕竟,我不应该期望将用法从一种语言转移到另一种语言),这样做的正确方法是什么?
E.g。类似的东西(愚蠢的例子如下......)
(defun f (x) (
(let* ((x 4)
(y (1+ x))
(flet ((g (x) (+ 2 x)))
(g y))))
答案 0 :(得分:1)
您想知道它之间是否存在差异:
(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
或递归一起使用。然后它会在每次迭代时完成计算,而不是在调用之前完成一次。这些是真正重要的案例。