tags:

views:

1056

answers:

2

This works:

(+ 1 2 3)
6

This doesn't work:

(+ '(1 2 3))

This works if 'cl-*' is loaded:

(reduce '+ '(1 2 3))
6

If reduce were always available I could write:

(defun sum (L)
  (reduce '+ L))

(sum '(1 2 3))
6

What is the best practice for defining functions such as sum?

+1  A: 

This ought to do the trick:

(defun sum-list (list)
  (if list
      (+ (car list) (sum-list (cdr list)))
    0))

[source]

Edit: Here is another good link that explains car and cdr - basically they are functions that allow you to grab the first element of a list and retrieve a new list sans the first item.

Andrew Hare
Recursion is *bad* in Emacs Lisp.
kmkaplan
why is recursion bad?
Peter Miehle
I was trying to avoid doing exactly that.
J.F. Sebastian
Most of the time, you should be able to use reduce and the varieties of map operations instead of explicitly handling cars and cdrs.
Svante
Because Emacs Lisp does not do tail call optimization. What’s more your sum-list recursion is *not* in tail position.
kmkaplan
Good to know! I am still learning all the ins and outs of Lisp myself.
Andrew Hare
Then you have an exercice: rewrite your function so that it runs in constant space.
kmkaplan
Yikes! I will see what I can do :)
Andrew Hare
@kmkaplan: Shouldn't `if` be short-circuited? In that case `sum-list` is in a tail-recursion position, isn't it?
J.F. Sebastian
The if is not the problem. The problem is the (+ ... (sum-list ...)). This creates a new frame so that computation of the + function can be done once sum-list returns.
kmkaplan
@kmkaplan: (defun sum-iter (L total) (if L (sum-iter (cdr L) (+ (car L) total)) total)) ? (sum-iter '(1 2 3) 0) -> 6
J.F. Sebastian
Yes. But remember not to do it with Emacs Lisp, just with Lisps that give you tail call optimization.
kmkaplan
+11  A: 
(apply '+ '(1 2 3))
kmkaplan
Thanks. I've thought that I'm missing something trivial.
J.F. Sebastian