Common Lisp-类型检查两个变量

时间:2018-10-04 00:56:44

标签: lisp common-lisp

嗨,我是Common Lisp的初学者。我想检查两个变量是否为整数。如果n和m均为整数,我希望它返回-如果它为负,0如果它为零,+如果它为正,NIL如果它为负对于n和m都不是整数。我想出了如何使用一个变量来执行此操作,但似乎无法弄清楚如何使用两个变量来执行此操作。谢谢。

这是一个采用数字参数的代码,如果为负,则返回-;如果为零,则返回0;如果为正,则返回+;如果为负,则返回NIL它不是整数:

(defun sign (n)
 (if(typep n 'integer)
    (cond ((< n 0) '-)
          ((= n 0) 0)
          ((> n 0) '+))))

每种情况的输出为:

CL-USER> (sign 3) 

+

CL-USER> (sign -3) 

-

CL-USER> (sign 0) 

0

CL-USER> (sign 3.3)

NIL

这是我检查两个变量的代码,我希望它检查n和m是整数,以及n和m是正数,负数还是零:

(defun sign (n m)
 (if (and (typep n 'integer) (typep m 'integer))
  (cond (and ((< n 0) '-) ((< m 0) '-))
        (and ((= n 0) 0) ((= m 0) 0))
        (and ((> n 0) '+) ((> m 0) '+)) ))))

4 个答案:

答案 0 :(得分:3)

记住基本的Lisp语法。函数调用和一些基本表达式写为

(operator argument-0 argument-1 ... argument-n)

对吗?

开括号,运算符,参数0,自变量1 ...自变量-n,右括号。

现在,如果我们拥有(< n 0)(< m 0)AND表达式将如何?

(and (< n 0) (< m 0))

但是你写:

and ((< n 0) '-) ((< m 0) '-)

您有以下错误:

  • AND表达式周围没有括号。
  • 在参数表达式周围加上括号。
  • '-混入了参数表达式。

现在COND期望:

(COND (testa1 forma0 forma1 ... forman)
      (testb1 formb1 formb1 ... formbn)
      ...
      (testm1 formm0 formm1 ... formmn))

所以不是

(defun sign (n m)
  (if (and (typep n 'integer) (typep m 'integer))
      (cond (and ((< n 0) '-) ((< m 0) '-))
            (and ((= n 0)  0) ((= m 0)  0))
            (and ((> n 0) '+) ((> m 0) '+)))))

顺便说一句,最后还有一个括号。

我们写:

(defun sign (n m)
  (if (and (typep n 'integer) (typep m 'integer))
      (cond ((and (< n 0) (< m 0)) '-)
            .... )))

还可以使用integerpminuspzeropplusp之类的谓词。

答案 1 :(得分:2)

您可以使用已经运行且经过测试的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)

请注意,一般来说,这很重要, 您选择哪种平等测试:

;; 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=)

答案 2 :(得分:1)

您似乎使用了正确的方法,只是迷惑了括号。您的每个cond案例看起来都是

(and ((< n 0) '-) ((< m 0) '-))

我想你的意思

((and (< n 0) (< m 0)) '-)

对于其他两种情况,都是相同的。

答案 3 :(得分:0)

编写sign的另一种紧凑方式是使用标准函数signum

  

根据数字是否为负数,返回-1、0或1中的一个,   零或正数

代码如下:

(defun sign (n)                                                                                                                                                                                                                                                     
  (when (integerp n)                                                                                                                                                                                                                                                            
    (case (signum n)                                                                                                                                                                                                                                                              
      (-1 '-)                                                                                                                                                                                                                                                                     
      (0   0)                                                                                                                                                                                                                                                                       
      (1  '+))))