Правильный способ программирования на Лиспе? - PullRequest
4 голосов
/ 24 сентября 2011

Я новичок в Common Lisp и обнаружил, что пользуюсь тем, как функции возвращают значения.Ниже приведены два тривиальных примера:

(defun safe-avg (a b)
    (and (numberp a) (numberp b) (/ (+ a b) 2)))

(defun safe-div (a b)
    (and (numberp a) (numberp b) (> b 0) (/ a b)))

Но я мог бы написать это так (возможно, яснее):

(defun safe-avg (a b)
    (if (and (numberp a) (numberp b))
        (/ (+ a b) 2)))

(defun safe-div (a b)
    (if (and (numberp a) (numberp b) (> b 0))
        (/ a b)))

Я хотел знать, какой метод предпочтительнеечто-то вроде этого и причины этого, прежде чем я начну злоупотреблять этой привычкой.

Ответы [ 2 ]

7 голосов
/ 24 сентября 2011

Поскольку вы не используете ветку "else", вы можете использовать when:

(defun safe-div (a b)
  (when (and (numberp a) (numberp b) (> b 0))
    (/ a b)))

, который совпадает с:

(defun safe-div (a b)
  (if (and (numberp a) (numberp b) (> b 0))
      (/ a b)
      nil))

, который совпадает сваша версия, но более явная.

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

Было бы лучше использовать условия, либо через объявления типов, либо через утверждения, либо через явныеwhensignal формы.Затем вы можете определить обработчики и перезапустить для этих условий для всех частей вашей программы.Дальнейшее чтение: Практический Common Lisp, гл.19 .

В этом случае я бы вообще здесь не занимался:

(defun safe-div (a b)
  (/ a b))

(точнее, просто используйте /).

Если / получит неверные аргументы, это будет сигнализировать об ошибке, которую вы можете затем обработать снаружи, где вы знаете, что это может означать.

3 голосов
/ 24 сентября 2011

Первая форма идиоматически приемлема.Это не лучший пример эффективного использования возвращаемого значения AND, поскольку вторая форма немного понятнее, но не длиннее.Но вы не должны бояться использовать LISP по назначению!

Например, идти в (нецелесообразном) направлении ... кто-то может возразить, что неявное «нулевое возвращение» операторов if может сбить с толкуи попробуйте параллельную if/else структуру, чтобы быть более ясной:

(defun safe-avg (a b)
  (cond ((and (numberp a) (numberp b))
         (/ (+ a b) 2))
        (t
         nil)))

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

...