Defun with a list as an argument

I am trying to take Lisp as my new language, and I am having some problems regarding how part of the functions work on every element of the list passed to it.

In order to learn how to get around this, I am trying to write a fairly basic division form, not screaming when one of the list items is 0 (but instead just returns 0)

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

I am trying to run this as:

 (divtest '(20 2 5)) 

What gives:

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

The point of failure seems to be due to the fact that I do not "retrieve" the items in the list before passing them to the functions (in this case, neither / dolist works as intended, since x never evaluates to 0). If I'm right, can someone tell me how to do this β€œextraction”?


Note. This question is related to the one I asked earlier , but since I do not understand how much of the previous answer actually allowed him to work as expected with this particular problem, I decided to go further into the basics

+6
source share
4 answers

/ takes one or more numbers as arguments, but in your code you pass it a list - it is clear that this will not work. The apply function is your friend here - (apply #'foo ab (list cde)) equivalent to (foo abcde) . Note that the apply arguments between the function used and the destination list are optional, therefore (apply #'/ '(20 2 5)) equivalent to (/ 20 2 5) .

Also, trying to remove zeros will not work. dolist evaluates its body for each element in the elements argument list, but you actually do nothing to change the contents of the elements (the result of computing the dolist body dolist not reassigned to the original element as you seem to expect).

The remove-if functions (and its destructive counterpart delete-if ) are what you are looking for. The following shows how to use it (it takes a lot of optional arguments that you don't need to worry about for this purpose).

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

Also note that this will not lead correctly if the elements list does not have zero as the first element (if I understand what the function should do). So you may want something like

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

See Hyperspec for details.

+5
source

Or you can write it like this:

 (defun divtest (elements) (if (member 0 elements) 0 (apply #'/ elements))) 
+1
source
 (block exit (reduce #'/ '(1 2 3 0 5) :key (lambda (x) (if (zerop x) (return-from exit 0) x)))) 
+1
source

Try (apply / elements) instead of (/ elements) . I think (?) That should work on most Lisp dialects.

0
source

Source: https://habr.com/ru/post/906520/


All Articles