Reputation: 1
I've just started to play around with Lisp (Common-Lisp), here's a function that calculates the average of a list of numbers
CL-USER> (defun average (list) (/ (apply #'+ list) (length list)))
AVERAGE
CL-USER> (average '(1 2 3 4))
5/2
however if I rewrite the function like so
CL-USER> (defun average (list) (/ (+ list) (length list)))
it doesn't work since (+ '(list-of-numbers)) can't be evaluated, hence the arguement of length and the expression in the + are incompatible.
is there a way of cajoling (list) to be evaluated naturally as an expression by + and passed as data to length ? rather than using apply #'
I've tried this:
(defun average (list) (/ (+ list) (length '(list))))
but this doesn't seem to do it either !
Upvotes: 0
Views: 178
Reputation: 139261
There is no reason not to use APPLY
or, better, REDUCE
. Here REDUCE
is the correct function.
If you program in Lisp, most of the time you have to use a symbol, naming your operation, followed by arguments. This is the general basic expression style in Lisp. You might expect that there are shorter ways to write something like reducing a list with a function. But there isn't, in basic Lisp.
(+ (list 1 2 3 4))
is an error because +
expects numbers, not a list.
If you want to sum all numbers in a list, you have to use REDUCE
. This operation is also known as folding.
Summing the numbers in a list:
(reduce #'+ (list 1 2 3 4))
Another simple way is to use LOOP
:
(loop for n in (list 1 2 3 4) sum n)
Writing something like (length '(list))
makes no sense, since you are quoting a list. A quoted list is treated as data and not code. Since it is constant data, the result is always 1
.
One of the Lisp ways to get to short programs is to build up a vocabulary of reusable functions. One doesn't use the shortest notation, but instead one is creating reusable functions with obvious names. Thus, if we sum a lot, we write a sum
function:
(defun sum (list)
(reduce #'+ list))
Then average
is:
(defun average (list)
(/ (sum list) (length list)))
Upvotes: 5
Reputation: 799
See Common lisp: How many argument can a function take?
It would be preferable to use (reduce #'+ list)
instead (apply #'+ list)
because apply
is subject to the limit of number of argument a that function can take.
So your average function should looks like:
(defun average (list)
(/ (reduce #'+ list)
(length list)))
BTW, the code (length '(list))
returns 1 because it returns the lenght of a list containing the symbol "list".
Upvotes: 5