2014-05-12 28 views
0

嵌套在FLET/LABELS块中的LET块是否被认为是惯用或非惯用的?我试图模仿Haskell中的通用where块(所以我有defun,我想编写使用某些临时绑定来实现值和函数的代码。LET块内部嵌套的FLET块(反之亦然)

在情况下,这些都是非惯用的(毕竟,我不应该期望使用从一种语言转移到另一个),什么是应该做的正确方法?

例如像(愚蠢的例子如下...)

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

你有一些括号错误;也没有使用函数参数'x'。 – uselpa

+0

我想,既然你说过“习惯用法”,可以通过调查现有代码,并查看这种情况发生的频率,来客观地回答这个问题,但即使如此,你也必须决定哪些代码是惯用的,哪些不是。因此,我认为这可能有点过于主观。也就是说,在flet内部没有任何问题,或者让flet进入内部。如果你想模仿Haskell结构,我不会为编写惯用代码而担心,尽管如此;只是担心与自己的代码一致。 –

+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 

由于函数使用自由变量,所以切换顺序现在不可能移动逻辑。你可以把letg这样的定义中:

(defun f (x) 
    (flet ((g (z) ; renamed to not shadow original x 
      (let* ((y (1+ x))) 
      (+ 2 z y)))   
    (g x)))) 

但是想象一下,你mapcarreduce或递归使用它。然后它会在每次迭代中完成计算,而不是在调用之前进行一次计算。这些真的很重要。