defun со списком в качестве аргумента - PullRequest
6 голосов
/ 21 января 2012

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

С целью научиться обходить это, я пытаюсь написать довольно простую форму деления, которая не каркается, когда один из элементов списка равен 0 (а вместо этого просто возвращает 0)

(defun divtest (elements)
  (dolist (x elements)
    (if (zerop x) 0 () )
  (/ elements)))))

Я пытаюсь запустить это как:

(divtest '(20 2 5))

Что дает:

*** - /: (20 2 5) is not a number

Кажется, причина неудачи коренится в том факте, что я не "извлекаю" элементы из списка перед передачей их в функцию (в этом случае ни /, ни dolist не работают должным образом, поскольку x никогда не вычисляет 0). Если я прав, может кто-нибудь сказать мне, как выполнить это "извлечение"?


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

Ответы [ 4 ]

5 голосов
/ 21 января 2012

/ принимает в качестве аргументов одно или несколько чисел, но в вашем коде вы передаете ему список - очевидно, это не будет работать.Функция apply здесь ваш друг - (apply #'foo a b (list c d e)) эквивалентно (foo a b c d e).Обратите внимание, что аргументы apply между используемой функцией и окончательным списком являются необязательными, поэтому (apply #'/ '(20 2 5)) эквивалентно (/ 20 2 5).

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

Функции remove-if (и его разрушительный аналог, delete-if) - это то, что вы ищете.Ниже показано, как его использовать (для этого требуется множество необязательных аргументов, о которых вам не нужно беспокоиться для этой цели).

(defun divtest (elements)
  (apply #'/ (remove-if #'zerop elements)))

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

(defun divtest (elements)
  (apply #'/ (first elements) (remove-if #'zerop (rest elements))))

См. Hyperspec для более подробной информации.

1 голос
/ 22 января 2012
(block exit
  (reduce #'/ '(1 2 3 0 5)
          :key (lambda (x)
                 (if (zerop x)
                     (return-from exit 0)
                   x))))
1 голос
/ 21 января 2012

Или вы можете написать это так

(defun divtest (elements)
  (if (member 0 elements)
      0
      (apply #'/ elements)))
0 голосов
/ 21 января 2012

Попробуйте (apply / elements) вместо (/ elements).Я думаю (?), Что должно работать на большинстве диалектов Лисп.

...