5

I assumed that values passed into a lisp function are assigned to a quote matching the name of the parameter. However, I was surprised that this:

(defun test (x) (print (eval 'x)))
(test 5)

doesn't work (the variable x is unbound). So if parameters aren't stored as symbols in the function, what exactly IS x in this example? Is there a way to access parameters from a symbol matching the parameter name?

More context: What I would like to do is something like this:

defun slice (r1 c1 r2 c2 board)
  (dolist (param '(r1 c1 r2 c2))  ;adjust for negative indices
    (if (< (eval param) 0)
      (set param (+ (length board) (eval param)))))
        ;Body of function

Basically, I want to iterate through the first four parameters and make an adjustment to any of their values if they are < 0. Of course, I could do a let and have an individual line for each parameter, but considering I'm doing the same thing for each of the four parameters this seemed cleaner. However, I get the error that the variable R1 is unbound.

rcorre
  • 6,477
  • 3
  • 28
  • 33

3 Answers3

5

That's basically how lexical binding works: the variable name gets replaced within the lexical scope with a direct reference to where the variable's value is stored. Binding the variable name's symbol-value is only done for dynamic variable which you can declare with special.

One way to avoid repeating yourself would be a macro:

(defmacro with-adjusting ((&rest vars) adjust-value &body body)
  `(let ,(loop for var in vars
               collect `(,var (if (minusp ,var)
                                (+ ,var ,adjust-value)
                                ,var)))
     ,@body))

(defun slice (r1 c1 r2 c2 board)
  (with-adjusting (r1 c1 r2 c2) (length board)
    ;; function body
Rörd
  • 6,556
  • 21
  • 27
4

Is there a way to access parameters from a symbol matching the parameter name?

Not for lexical binding. Common Lisp gives no way to access a lexical variable from a similar named symbol. You would need to declare the variable special.

So if parameters aren't stored as symbols in the function, what exactly IS x in this example?

A processor register? A part of a stack frame?

With dynamic binding:

CL-USER 40 > (defun foo (a b)
               (declare (special a b))
               (dolist (v '(a b))
                 (if (zerop (symbol-value v))
                     (set v 10)))
               (values a b))
FOO

CL-USER 41 > (foo 1 0)
1
10
Rainer Joswig
  • 136,269
  • 10
  • 221
  • 346
  • Thanks, this allowed me to use the same code with just one extra line to declare the parameters as special – rcorre Oct 16 '13 at 21:29
  • 2
    @murphyslaw Do be sure that you understand the other possible consequences of declaring a variable special. The variable will be bound with dynamic scope which means, e.g., that `(let ((x 3)) (declare (special x)) (funcall (let ((x 4)) (declare (special x)) (lambda () x))))` will return `3`, not `4`, even though when the `lambda` function is created `x` is bound to `4`. – Joshua Taylor Oct 16 '13 at 23:10
  • @JoshuaTaylor - Thanks for the heads up, I clearly need do do some more reading on this. Just to be sure, declaring a parameter as special will not have any implications for that symbol outside of the function block, correct? – rcorre Oct 17 '13 at 16:07
  • I suppose it depends on what exactly you mean by outside, but take a look at [these examples](http://pastebin.com/ApY9zNmV). – Joshua Taylor Oct 17 '13 at 19:44
2

As Rainer explained, you cannot access the lexical argument value by its name.

What you can do instead is use the &rest argument together with destructuring-bind if you want the variables too:

(defun slice (board &rest params)
  (destructuring-bind (r1 c1 r2 c2)
      (mapcar (lambda (param) ;adjust for negative indices
                (if (minusp param)
                    (+ (length board) param)
                    param))
              params)
    ... operate on r1 c1 r2 c2 ...))
sds
  • 58,617
  • 29
  • 161
  • 278