用Lisp编程的正确方法?

用Lisp编程的正确方法?,lisp,common-lisp,Lisp,Common Lisp,我不熟悉Common Lisp,发现自己利用了函数返回值的方式。以下是两个简单的例子: (defun safe-avg (a b) (and (numberp a) (numberp b) (/ (+ a b) 2))) (defun safe-div (a b) (and (numberp a) (numberp b) (> b 0) (/ a b))) 但我可以这样写(可以说更清楚): 在我开始滥用这种习惯之前,我想知道做这种事情的首选方法是什么,以及背后的原因。第

我不熟悉Common Lisp,发现自己利用了函数返回值的方式。以下是两个简单的例子:

(defun safe-avg (a b)
    (and (numberp a) (numberp b) (/ (+ a b) 2)))

(defun safe-div (a b)
    (and (numberp a) (numberp b) (> b 0) (/ a b)))
但我可以这样写(可以说更清楚):


在我开始滥用这种习惯之前,我想知道做这种事情的首选方法是什么,以及背后的原因。

第一种形式在习惯上是可以接受的。这并不是有效使用
返回值的最佳示例,因为第二种形式更加清晰,没有任何长度。但是您不应该害怕按照预期使用LISP

例如,朝着一个(不可取的)方向走……有人可能会认为
if
语句隐含的“nil return”可能会让人困惑,并尝试将
if/else
结构平行化,以便更清楚:

(defun safe-avg (a b)
  (cond ((and (numberp a) (numberp b))
         (/ (+ a b) 2))
        (t
         nil)))
那太糟糕了。你不想走那条路。因此,请继续使用表达式,通过良好的计算来减少代码量,并使用注释来弥补不足,以提醒其他人(和您自己)如果有任何不明显的地方,它是如何工作的。

因为您不使用“else”分支,所以可以在
时使用

(defun safe-div (a b)
  (when (and (numberp a) (numberp b) (> b 0))
    (/ a b)))
这与:

(defun safe-div (a b)
  (if (and (numberp a) (numberp b) (> b 0))
      (/ a b)
      nil))
这与您的版本相同,但更明确

无论如何,这些都是功能上等价的。我宁愿考虑如何使用这些功能。如果您这样做,那么每次调用这些函数时都必须进行空检查,这很繁琐

最好使用条件,或者通过类型声明、断言,或者通过显式
when
signal
表单。然后,您可以为程序的整个部分定义这些条件的处理程序并重新启动。进一步阅读:

在这种情况下,我根本不会在这里处理这个问题:

(defun safe-div (a b)
  (/ a b))
(或者更确切地说,只需使用
/


如果
/
得到错误的参数,它将发出一个错误信号,然后您可以在外部处理,您知道这可能意味着什么。

我将使用第二种形式。为什么?因为它“不那么棘手”,更能显示意图。我重视代码的可读性——包括现在和6个月后。我习惯于scheme,你确定函数是等效的吗?对我来说不是,因为如果约束不满足,第一对函数返回false,第二个函数似乎没有指定返回值啊,这很有趣。我来自函数式编程的思维模式,未定义的结果很糟糕。:-)@斯万特-乱码怎么了?它复制并粘贴到我使用
sudo apt get install clisp获得的解释器中,并且似乎按照预期工作。什么不起作用?另外,由于您在试图演示“不要这样做”的代码体上进行了挑选,因此您没有抓住要点。@HostileFork:通常,您将测试包装在and中,并将返回值放在条件之外。但是,如果COND没有返回值,它将返回测试的值,因此这(可能是意外地)起作用。@ArtTaylor:现在,COND通常是if之上的一个宏。@HostileFork您将
(/(+ab)2)
放在
子句中。这就是斯万特所说的。我已经修好了。
(defun safe-div (a b)
  (/ a b))