在Lisp中编程的正确方法?

时间:2011-09-24 08:03:27

标签: 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)))

但我可以这样写(可以说更清楚):

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

(defun safe-div (a b)
    (if (and (numberp a) (numberp b) (> b 0))
        (/ a b)))

在我开始滥用这个习惯之前,我想知道做这样的事情及其背后的推理的首选方法是什么。

2 个答案:

答案 0 :(得分:7)

由于您不使用“else”分支,因此可以使用when

(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形式来使用条件。然后,您可以为程序的整个部分定义处理程序并重新启动这些条件。进一步阅读:Practical Common Lisp, ch. 19

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

(defun safe-div (a b)
  (/ a b))

(或者更确切地说,只使用/)。

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

答案 1 :(得分:3)

第一种形式是惯用的。这不是有效使用AND的返回值的最佳示例,因为第二种形式更清晰,没有任何更长。但你不应该害怕按预期使用LISP!

例如,进入一个(不可取的)方向......有人可能会争辩说if陈述的隐含“无回报”可能会让人感到困惑,并尝试并行if/else结构更清晰:

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

那很糟糕。你不想走那条路。因此,继续使用表达式并使用良好的评估来修改代码量,并使用注释来获取松弛以提醒其他人(以及您自己)如果有任何不明显的事情它将如何工作。