Определить тип треугольника в Лиспе


Это простая программа Лисп читать в три стороны треугольника и доклад о каком треугольнике она является (или не является). Любая обратная связь будет высоко ценится.

(defun read-side (side) (format t "Enter a value for side ~d: ~%" side) (read))

(defun is-a-triangle (a b c) (if (and (< a (+ b c)) (< b (+ a c)) (< c (+ a b))) t nil))

(defun is-equilateral (a b c) (if (and (= a b c)) t nil))

(defun is-isoceles (a b c) (if (or (= a b) (= b c)) t nil))

(defun is-right-triangle (a b c) 
  (let ((square-of-short-sides-sum 0) (short-sides ()) (large-side 0) (sides (list a b c))) 
    (loop for p in sides do 
      (if (> p large-side) 
        (progn (if (/= 0 large-side) (setq short-sides (append short-sides (list large-side)))) 
        (setq large-side p))
        (setq short-sides (append short-sides (list p)))))
    (format t "short-sides: ~a ~%" short-sides)
    (format t "large-side: ~a ~%" large-side)
    (loop for p in short-sides do 
      (setq square-of-short-sides-sum (+ square-of-short-sides-sum (expt p 2))))
    (if (= (expt large-side 2) square-of-short-sides-sum) t nil)))

(defun status-message (message a b c) (format t "The shape ~d,~d,~d ~a ~%" a b c message))

(let ((a (read-side 1)) (b (read-side 2)) (c (read-side 3)))
  (status-message "is being checked..." a b c)
  (if (is-equilateral a b c) (status-message "is an equilateral triangle." a b c)
      (if (is-a-triangle a b c)
        (progn (if (is-isoceles a b c) (status-message "is an isoceles triangle." a b c)
            (if (is-right-triangle a b c) (status-message "is a right triangle." a b c)
                (status-message "is a non-isoceles, non-equilateral, non-right triangle." a b c))))
        (status-message "is not a triangle." a b c))))

Спасибо предыдущим комментаторам за ваши предложения. С тех пор я изменил код, основанный на обратной связи я получил, и я отправляю измененный код ниже. Если у вас есть какие-либо отзывы по этой новой редакции, то это можно только приветствовать. Спасибо!

(defun read-side (side) (format t "Enter a value for side ~d: ~%" side) (read))

(defun triangle-p (a b c) (and (< a (+ b c)) (< b (+ a c)) (< c (+ a b))))

(defun equilateral-p (a b c) (= a b c))

(defun isoceles-p (a b c) (or (= a b) (= b c)))

(defun right-triangle-p (a b c) 
  (destructuring-bind (long-side &rest short-sides) (sort (list a b c) #'>)
    (= (expt long-side 2) (+ (expt (first short-sides) 2) (expt (second short-sides) 2)))))

(defun status-message (message a b c) (format t "The shape ~d,~d,~d ~a ~%" a b c message))

(defun classify-triangle (a b c)
  (cond ((not (triangle-p a b c)))
    ((right-triangle-p a b c) 'right)
    ((equilateral-p a b c) 'equilateral)
    ((isoceles-p a b c) 'isoceles)
    (t 'triangle)))

(let (triangle-type (a (read-side 1)) (b (read-side 2)) (c (read-side 3)))
  (format t "classify triangle says ~a ~%" (classify-triangle a b c))
  (setq triangle-type (classify-triangle a b c))
  (cond ((eq 'right triangle-type) (status-message "is a right triangle." a b c))
    ((eq 'equilateral triangle-type) (status-message "is an equilateral triangle." a b c))
    ((eq 'isoceles triangle-type) (status-message "is an isoceles triangle." a b c))
    ((eq 'triangle triangle-type) (status-message "is a non-right, non-isoceles, non-equilateral triangle." a b c))
    (t (status-message "is not a triangle." a b c))))

Вот последняя редакция:

(defun read-side (side) (format t "Enter a value for side ~d: ~%" side) (read))

(defun triangle-p (a b c) (and (< a (+ b c)) (< b (+ a c)) (< c (+ a b))))

(defun equilateral-p (a b c) (= a b c))

(defun isoceles-p (a b c) (or (= a b) (= b c)))

(defun right-triangle-p (a b c) 
  (destructuring-bind (long-side &rest short-sides) (sort (list a b c) #'>)
    (= (expt long-side 2) (+ (expt (first short-sides) 2) (expt (second short-sides) 2)))))

(defun status-message (message a b c) (format t "The shape ~d,~d,~d ~a ~%" a b c message))

(defun classify-triangle (a b c)
  (cond ((not (triangle-p a b c)))
    ((right-triangle-p a b c) 'right)
    ((equilateral-p a b c) 'equilateral)
    ((isoceles-p a b c) 'isoceles)
    (t 'triangle)))

(let* ((a (read-side 1)) (b (read-side 2)) (c (read-side 3)) (triangle-type (classify-triangle a b c)))
  (format t "classify triangle says ~a ~%" triangle-type)
  (cond ((eq 'right triangle-type) (status-message "is a right triangle." a b c))
    ((eq 'equilateral triangle-type) (status-message "is an equilateral triangle." a b c))
    ((eq 'isoceles triangle-type) (status-message "is an isoceles triangle." a b c))
    ((eq 'triangle triangle-type) (status-message "is a non-right, non-isoceles, non-equilateral triangle." a b c))
    (t (status-message "is not a triangle." a b c))))

После прочтения Вашего предложения на мой вопрос сортировки, а затем читал о 'формат', я попыталась написать заявление формат, чтобы упростить логику в нижней части кода. Я не мог выяснить, как сделать условный формат, основанный на символе, так что вместо этого я определить виды треугольника как глобальные переменные с defineparameter' (есть ли лучший способ для определения константы?). Я также использовал петли формате, который вы описали в своем ответе на мой-рода-3 вопрос, чтобы сократить выражение. Новый код выглядит следующим образом:

(defparameter *right* 0)
(defparameter *equilateral* 1)
(defparameter *isoceles* 2)
(defparameter *triangle* 3)
(defparameter *non-triangle* 4)
(defun read-side (side) (format t "Enter a value for side ~d: ~%" side) (read))

(defun triangle-p (a b c) (and (< a (+ b c)) (< b (+ a c)) (< c (+ a b))))

(defun equilateral-p (a b c) (= a b c))

(defun isoceles-p (a b c) (or (= a b) (= b c) (= a c)))

(defun right-triangle-p (a b c) 
  (destructuring-bind (long-side &rest short-sides) (sort (list a b c) #'>)
    (= (expt long-side 2) (+ (expt (first short-sides) 2) (expt (second short-sides) 2)))))

(defun status-message (message a b c) (format t "The shape ~d,~d,~d ~a ~%" a b c message))

(defun classify-triangle (a b c)
  (cond ((not (triangle-p a b c)) *non-triangle*)
    ((right-triangle-p a b c) *right*)
    ((equilateral-p a b c) *equilateral*)
    ((isoceles-p a b c) *isoceles*)
    (t *triangle*)))

(let* ((a (read-side 1)) (b (read-side 2)) (c (read-side 3)) (triangle-type (classify-triangle a b c)))
  (format t "classify triangle says ~a ~%" triangle-type)
  (format t "The shape (~{~d~^,  ~}) is ~[a right~;an equilateral~;an isoceles~;a non-right, non-isoceles, non-equilateral~;not a~] triangle." (list a b c) triangle-type))

Спасибо всем, за ваши отзывы. Вот последняя редакция.

(defun read-side (side) (format t "Enter a value for side ~d: ~%" side) (read))

(defun triangle-p (a b c) (and (< a (+ b c)) (< b (+ a c)) (< c (+ a b))))

(defun equilateral-p (a b c) (= a b c))

(defun isoceles-p (a b c) (or (= a b) (= b c)))

(defun right-triangle-p (a b c) 
    (destructuring-bind (long-side short-side-1 short-side-2) (sort (list a b c) #'>)
          (= (expt long-side 2) (+ (expt short-side-1 2) (expt short-side-2 2)))))

(defun status-message (message a b c) (format t "The shape ~d,~d,~d ~a ~%" a b c message))

(defun classify-triangle (a b c)
    (cond ((not (triangle-p a b c)) nil)
          ((right-triangle-p a b c) 'right)
              ((equilateral-p a b c) 'equilateral)
              ((isoceles-p a b c) 'isoceles)
                  (t 'triangle)))

(let* ((a (read-side 1)) (b (read-side 2)) (c (read-side 3)) 
    (triangle-type (classify-triangle a b c))
    (article (if (member triangle-type '(isoceles equilateral)) "an" "a"))
    (tri-name (if (eq triangle-type 'triangle) "non-right, non-isoceles, non-equilateral" triangle-type)))
    (format t "The shape (~d, ~d, ~d) is ~:[not a triangle~;~a ~(~a~) triangle~]." a b c triangle-type article tri-name))


1403
4
задан 7 марта 2011 в 04:03 Источник Поделиться
Комментарии
1 ответ

Имейте в виду, что каждая форма в возвращает шепелявить чего-то. (и Foo бар баз) возвращает ноль , если функция Foo, бар или баз равен нулю, и т , если их оценивать непропустит. Это означает, что в любом месте вы пишете (если (и ...) Т шь), вы можете просто написать (и ...) с тем же эффектом. То же самое относится к (Если (или ...) Т шь) и (или ...), а также (если (= ...) т шь) и (= ...). Ваш это-равносторонний является особо вопиющим нарушением этого; он может быть написан как просто

(defun equilateral-p (a b c) (= a b c))


Наиболее распространенные конвенции для предикатов в общий Лисп является прекращение функции наименование С П или , а не предварив его с это- (лично я предиката имена ?, в соответствии с Конвенцией схему, но это не стандарт).


Ваш -правильный треугольник функция может быть упрощена большое , сняв с ведением операций и использование более функционального подхода. Я бы написал его так:

(defun right-triangle-p (a b c)
(destructuring-bind (long-side &rest short-sides) (sort (list a b c) #'>)
(= (expt large-side 2)
(+ (expt (car short-sides) 2) (expt (cadr short-sides 2))))))

Как правило, всякий раз, когда вы используете цикл для присвоения значений промежуточных переменных через setq, дважды проверьте, что вы нужны петли на всех. Я обнаружил, что это часто (хотя и не всегда) лишнее.

Редактировать: если вы берете мой совет о том, как определить другое назначение в качестве функции можно написать

...
(destructuring-bind (long-side &rest short-sides) (my-sort-3 a b c)
...


Окончательный дай структура может быть упрощена с помощью Конд вместо вложенных если, и слегка перестановке пунктов.

(let ((a (read-side 1)) (b (read-side 2)) (c (read-side 3)))
(cond ((not (triangle-p a b c)) (status-message "is not a triangle." a b c))
((equilateral-triangle-p a b c) (status-message "is an equilateral triangle." a b c))
((isoceles-triangle-p a b c) (status-message "is an isoceles triangle." a b c))
((right-triangle-p a b c) (status-message "is a right triangle." a b c))
(t (status-message "is a non-isoceles, non-equilateral, non-right triangle." a b c))))


Вы, возможно, захотите, чтобы повторно пишут, что окончательное дайте инструкцию как функция, которая возвращает тип треугольника (так как 'isoceles вместо печати "формы А,B,C-это isoceles треугольника.\н"), так что вы можете использовать его более легко. Это в основном те же советы, которые я давал вам на вашу функцию сортировки.


На чуть более общем плане, вы, возможно, захотите, чтобы быть явными о том, что Лисп, который вы используете. Это однозначный в данном случае, поскольку я уверен, что петля - это ХЛ построить, но имейте в виду, что "сюсюкать" - это довольно большая семья языков,

2
ответ дан 7 марта 2011 в 03:03 Источник Поделиться