【问题标题】:Common Lisp - type checking two variablesCommon Lisp - 类型检查两个变量
【发布时间】:2018-10-04 00:56:43
【问题描述】:

您好,我是 Common Lisp 的初学者。我想检查两个变量是否为整数。如果 n 和 m 都是整数,我希望它返回 - 如果它是负数,0 如果它是零,+ 如果它是正数,NIL 如果它不是 n 和米。我想出了如何用一个变量来做到这一点,但我似乎无法弄清楚如何用两个变量来做到这一点。谢谢。

这是接受数字参数并返回 - 如果它是负数,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) '+)) ))))

【问题讨论】:

    标签: lisp common-lisp


    【解决方案1】:

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

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

    对吗?

    左括号,运算符,argument-0,argument-1 ... argument-n,右括号。

    现在,如果我们有 (&lt; n 0)(&lt; 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 等谓词。

    【讨论】:

      【解决方案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)
      

      注意,在普通的 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=)
      

      【讨论】:

      • equality-value里面的let不是必须的,但更重要的是,调用test应该用funccall来完成。
      • @coredump 啊谢谢 - 我总是很喜欢你的答案和 cmets! - 我在控制台更正了这个(funcall),但忘记在文本中更正它。确实,equality-value 内部的 let 是多余的 - 我会删除它。我在以前的代码方面想太多了:D。
      【解决方案3】:

      看起来你有正确的方法,只是迷失在括号中。您的每个 cond 案例看起来像

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

      我想你是说

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

      其他两种情况也一样。

      【讨论】:

        【解决方案4】:

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

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

        代码可能如下所示:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-07-04
          • 1970-01-01
          • 2019-05-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多