Вы можете использовать уже функционирующее и проверенное определение sign
- что типично для программы lispers.Первым наивным решением было бы:
(defun sign-for-two (n m)
(when (eql (sign n) (sign m))
(sign n))
;; (if (condition) return-value NIL)
;; is equivalent to
;; (when (condition) return-value)
Обратите внимание, для общего lisp важно, какой тест на равенство вы выберете:
;; only symbols - for object identity eq
;; symbols or numbers - for object identity eql
;; (in most tests the default)
;; eql for each component? also in lists equal
;; equal not only lists but also
;; arrays (vectors, strings), structures, hash-tables
;; however case-insensitive in case of strings
;; equalp
;; mathematical number equality =
;; specifically characters char=
;; case-sensitive string equality string=
В нашем случае, eql достаточно.
;; to avoid `(sign n)` to be evaluated twice,
;; you could store it using `let`
;; and call from then on the stored value
;; (which is less costly).
(defun sign-for-two (n m)
(let ((x (sign n)))
(when (eql x (sign m))
x)))
Или создайте тестер на равенство (функция проверки по умолчанию: #'eql
), который возвращает одинаково проверенное значение и, если не равно, NIL
:
(defun equality-value (x y &key (test #'eql))
(when (funcall test z y) z)))
;; and apply this general solution to our case:
(defun sign-for-two (n m)
(equality-value (sign n) (sign m)))
, и вы можете применитьequality-value
функция в будущем для функций, в которых вы хотите вернуть значение, когда оно проверено как «равное», и вы можете передать функцию через :test
независимо от того, подходит ли для этого случая функция равенства, отличная от eql
, например
(equality-value string1 string2 :test #'string=)