LET块内的嵌套FLET块(反之亦然)

时间:2014-05-12 06:00:38

标签: nested lisp let

LET块嵌套在FLET / LABELS块内是否被视为惯用或非惯用?

同样,我可能会出现这种错误,但我试图模仿Haskell中的通用where块(所以我有defun并且我想编写使用某些的代码值和函数的临时绑定。

如果这些都是非惯用的(毕竟,我不应该期望将用法从一种语言转移到另一种语言),这样做的正确方法是什么?

E.g。类似的东西(愚蠢的例子如下......)

(defun f (x) (
  (let* ((x 4)
         (y (1+ x))
         (flet ((g (x) (+ 2 x)))
            (g y))))

1 个答案:

答案 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 / labelslet / 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))))

但想象一下,您将它与mapcarreduce或递归一起使用。然后它会在每次迭代时完成计算,而不是在调用之前完成一次。这些是真正重要的案例。