Common Lisp - проверка типа двух переменных - PullRequest
0 голосов
/ 04 октября 2018

Привет, я новичок в Common Lisp.Я хочу проверить, являются ли две переменные целыми числами.Если n и m являются целыми числами, я хочу, чтобы он возвращал -, если он отрицательный, 0, если он равен нулю, +, если он положительный, и NIL, если он не является целым числом как для n, так и для 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) '+)) ))))

Ответы [ 4 ]

0 голосов
/ 08 октября 2018

Другой компактный способ записи sign состоит в использовании стандартной функции signum, которая

возвращает один из -1, 0 или 1 в зависимости от того, является ли числоявляется отрицательным, нулевым или положительным

Код может выглядеть следующим образом:

(defun sign (n)                                                                                                                                                                                                                                                     
  (when (integerp n)                                                                                                                                                                                                                                                            
    (case (signum n)                                                                                                                                                                                                                                                              
      (-1 '-)                                                                                                                                                                                                                                                                     
      (0   0)                                                                                                                                                                                                                                                                       
      (1  '+))))
0 голосов
/ 04 октября 2018

Запомните основной синтаксис 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)) '-)
            .... )))

Также можно использовать предикаты, такие как integerp, minusp, zerop и plusp.

0 голосов
/ 04 октября 2018

Вы можете использовать уже функционирующее и проверенное определение 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=)
0 голосов
/ 04 октября 2018

Похоже, у вас правильный подход и вы просто потерялись в скобках.Каждый из ваших cond случаев выглядит как

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

Я думаю, вы имели в виду

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

и то же самое для двух других случаев.

...