Page 1 of 1

Code for calculating difference of sets not working

Posted: Sat Jun 09, 2012 8:42 am
by kiwifreak3
Hi everyone,
I'm trying to write a program (in emacslisp) to calculate the difference of two lists; could someone give me a hint as to why my code is returning an error saying "invalid function...", when I try it on an example?
I'd be grateful for help,
Thanks

Code: Select all

(defun diff (A B)
; calculates A\B
(setq index 0)
(if (or (equal A []) (equal B []))
    (print A)
(; else:
(while (< index (length A))
(
(if (string-equal (elt A index) (car B))
    ((aset A index (elt A 0)) (setq A (cdr A)))
)
(setq index (+ index 1))
)
)
(diff (A (cdr B)))
)
)
)
(diff [1 a c 5] [1 3 "foo" 4 7])

Re: Code for calculating difference of sets not working

Posted: Sun Jun 10, 2012 12:06 am
by ramarren
In Lisp all parentheses are usually meaningful, they are not just grouping/block delimiters. In your case you have superfluous parentheses around the else branch of IF and around the body of WHILE. This makes the system interpret those as function calls, and an entire expression does not name a function.

Additionally even with this fixed your code will not work. In EmacsLisp arrays and lists are different types, and CAR and CDR will not work on the former. Also you shouldn't just SETQ variables. Establish variables with LET.

Re: Code for calculating difference of sets not working

Posted: Sun Jun 10, 2012 2:04 am
by kiwifreak3
Thanks a lot Ramarren, you really helped me out there... I see I made quite some mistakes; I think I've got rid of them now although I'm still using the setq command within the while-loop, because I can't quite figure out where I should put the end-bracket of let otherwise (- perhaps after the end-bracket of the while-loop?)
perhaps someone could look at my new code; I think I'm nearly there - it's just returning nil instead of A\B...
I'd be grateful!

Code: Select all

(defun diff (A B)
; calculates A\B
(if (or (equal 0 (length A)) (equal 0 (length B)))
   A
; else:
(let ((index 0))
(while (< index (length A))
(if (equal (elt A index) (car B))
    (aset A index (elt A 0)) (setq A (cdr A))
)
(setq index (+ 1 index))
)
)
(diff A (cdr B))
)
)
(diff '(a b c d e) '(d e f g h))

Re: Code for calculating difference of sets not working

Posted: Sun Jun 10, 2012 5:17 am
by ramarren
kiwifreak3 wrote:I think I've got rid of them now although I'm still using the setq command within the while-loop, because I can't quite figure out where I should put the end-bracket of let otherwise
Sorry, I misspoke, you shouldn't create variables with SETQ, because they will be set as global variables and leak out of your function, and it also risks changing a variable with the same name which belongs to a surrounding context. Inside a LET which establishes your own context for the variable using SETQ is fine.

You are trying to use both iteration and recursion, and modifying the list at the same time. This seems overly complicated. I suggest using a nested iteration and an accumulator variable. That is, use LET to initialize a variable to NIL, and then PUSH on it. To decide what to push use a loop over A. To check if an element of A is in B use MEMBER or implement an equivalent if you can only use primitives. Don't forget to return you accumulator (possibly REVERSE'd, if order seems important) and the end of the function.

Rather than using index and ELT to loop over lists you should probably either use DOLIST or at least a (while list-variable ... (setq list-variable (cdr list-variable))). Note that in EmacsLisp empty list is false, and so can be used as a termination condition.

Re: Code for calculating difference of sets not working

Posted: Sun Jun 10, 2012 6:23 am
by kiwifreak3
Tanks so much, that realy is so much more simple than my version...

Code: Select all

; calculates A\B
(let (C)
  (dolist (element A)
    (if (not (member element B))
	(push element C)
    )
  )
C
)
)
(diff '(a b a c d) '(c d e d e f))