Assign values to multiple variables

Discussion of Common Lisp
Post Reply
nomiz
Posts: 2
Joined: Fri Oct 01, 2010 7:46 am

Assign values to multiple variables

Post by nomiz » Fri Oct 01, 2010 7:56 am

Hi all,

To assign random values to multiple variables i tried:

Code: Select all

(defun foo (var1 var2 var3 var4)
  (mapcar #'(lambda (x)
	      (setq x (random 10))
	      (list var1 var2 var3 var4))
	  )
  )
What is the right way?

Thanks! :)

ramarren
Posts: 613
Joined: Sun Jun 29, 2008 4:02 am
Location: Warsaw, Poland
Contact:

Re: Assign values to multiple variables

Post by ramarren » Fri Oct 01, 2010 8:25 am

If you have a number of variables that you are performing the same operation on the right way is usually to use a collection, like an array or a dictionary.

Although I guess it is possible even though Common Lisp doesn't have locatives, with something like:

Code: Select all

(defmacro ref (place)
  (let ((new-value (gensym "NEW-VALUE")))
   `(lambda (,new-value)
      (setf ,place ,new-value))))

(defmacro refs (&rest places)
  (labels ((refs-aux (places)
             (when places
               (list* `(ref ,(car places)) (refs-aux (cdr places))))))
   `(list ,@(refs-aux places))))

(defun test-ref ()
  (let (var1 var2 var3 var4)
    (mapcar #'(lambda (x)
                (funcall x (random 10)))
            (refs var1 var2 var3 var4))
    (list var1 var2 var3 var4)))
Note that I am not saying this is a particularly good idea. You should rethink what you are really trying to accomplish. You should probably also read more about pass-by-value semantics, which is what CL uses.

Warren Wilkinson
Posts: 117
Joined: Tue Aug 10, 2010 11:24 pm
Location: Calgary, Alberta
Contact:

Re: Assign values to multiple variables

Post by Warren Wilkinson » Fri Oct 01, 2010 2:07 pm

As Ramarren said, having to bind multiple variables isn't a common occurance. What is the issue in context of the problem you are solving?
It sounds like you have a small list of random numbers and you want to label them, destructuring bind is probably the easiest way to do it. An array of numbers (or a list) might be better: you would write (elt vars 0) instead of var1. Using an array or list also lets you loop across all values easily.

If you really want to bind variables (and, ideally, the amount of variables is known) you could use let, multiple-value-bind, destructuring-bind, apply, progv or symbol-macros.

let

Code: Select all

(defun use-quantities ()
  (let ((q1 2)
	(q2 4)
	(q3 6)
	(q4 8)
	(q5 5)
	(q6 3)
	(q7 5))
    (format t "~%q1: ~a~%q2: ~a~%q3: ~a~%q4: ~a~%q5: ~a~%q6: ~a~%q7: ~a"
	    q1 q2 q3 q4 q5 q6 q7)))
Multiple-value-bind

Code: Select all

(defun quantities () (values 2 4 6 8 5 3 5))
(defun use-quantities ()
  (multiple-value-bind (q1 q2 q3 q4 q5 q6 q7) (quantities)
    (format t "~%q1: ~a~%q2: ~a~%q3: ~a~%q4: ~a~%q5: ~a~%q6: ~a~%q7: ~a"
	    q1 q2 q3 q4 q5 q6 q7)))
destructuring-bind

Code: Select all

(defun quantities () (list 2 4 6 8 5 3 5))
(defun use-quantities ()
  (destructuring-bind (q1 q2 q3 q4 q5 q6 q7) (quantities)
    (format t "~%q1: ~a~%q2: ~a~%q3: ~a~%q4: ~a~%q5: ~a~%q6: ~a~%q7: ~a"
	    q1 q2 q3 q4 q5 q6 q7)))
Apply

Code: Select all

(defun quantities () (list 2 4 6 8 5 3 5))
(defun use-quantities (q1 q2 q3 q4 q5 q6 q7)
  (format t "~%q1: ~a~%q2: ~a~%q3: ~a~%q4: ~a~%q5: ~a~%q6: ~a~%q7: ~a"
	  q1 q2 q3 q4 q5 q6 q7))
(apply #'use-quantities (quantities))
progv

Code: Select all

(defvar *q1*)
(defvar *q2*)
(defvar *q3*)
(defvar *q4*)
(defvar *q5*)
(defvar *q6*)
(defvar *q7*)
(defun quantities () (list 2 4 6 8 5 3 5))
(defun use-quantities ()
  (progv '(*q1* *q2* *q3* *q4* *q5* *q6* *q7*) (quantities)
    (format t "~%q1: ~a~%q2: ~a~%q3: ~a~%q4: ~a~%q5: ~a~%q6: ~a~%q7: ~a"
	    *q1* *q2* *q3* *q4* *q5* *q6* *q7*)))
symbol macros

Code: Select all

(defun quantities () (list 2 4 6 8 5 3 5))
(define-symbol-macro q1 (elt randoms 0)) ;; q1 will expand into (elt randoms 0), thus
(define-symbol-macro q2 (elt randoms 1)) ;; it will get the local binding of 'randoms'
(define-symbol-macro q3 (elt randoms 2))
(define-symbol-macro q4 (elt randoms 3))
(define-symbol-macro q5 (elt randoms 4))
(define-symbol-macro q6 (elt randoms 5))
(define-symbol-macro q7 (elt randoms 6))
(defun use-quantities ()
  (let ((randoms (quantities)))
    (format t "~%q1: ~a~%q2: ~a~%q3: ~a~%q4: ~a~%q5: ~a~%q6: ~a~%q7: ~a"
	    q1 q2 q3 q4 q5 q6 q7)))
Last edited by Warren Wilkinson on Thu Oct 07, 2010 12:34 pm, edited 1 time in total.
Need an online wiki database? My Lisp startup http://www.formlis.com combines a wiki with forms and reports.

JamesF
Posts: 98
Joined: Thu Jul 10, 2008 7:14 pm

Re: Assign values to multiple variables

Post by JamesF » Tue Oct 05, 2010 9:20 pm

Nomiz,

Your formatting suggests you're trying to apply a C-style solution in lisp, which can be done, but isn't such a good idea. When on ice, you're better off with skates :)
Rather than try to debug what may be a valiant struggle in the wrong direction, what problem are you actually trying to solve here?

In case it's helpful, it's considered bad form for a function to change the value of variables that it's given as arguments. It may also to remember that you don't need to create intermediate variables to hold the results of calculations - instead, you can operate directory on the value returned by a function call.
So, instead of creating a variable x, passing it to a function that assigns it a random value, and then passing it to another function that multiplies it by a suitable factor (say, 5), and then passing it on to yet another function that prints out the result, in CL you'd do something more like this:

Code: Select all

(defvar foo ()
  (format t "~A" (* 5 (random 10))))
- you print out the result of multiplying 5 by the result of calling (random) with an argument of 10.

nomiz
Posts: 2
Joined: Fri Oct 01, 2010 7:46 am

Re: Assign values to multiple variables

Post by nomiz » Wed Oct 06, 2010 1:22 am

Wow, guys thanks a lot for all the input and info! :D

You have helped me a lot understanding lisp programming.

Post Reply