我是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)))
在我开始滥用这个习惯之前,我想知道做这样的事情及其背后的推理的首选方法是什么。
答案 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)))
那很糟糕。你不想走那条路。因此,继续使用表达式并使用良好的评估来修改代码量,并使用注释来获取松弛以提醒其他人(以及您自己)如果有任何不明显的事情它将如何工作。