Thunfische
Thunfische

Reputation: 1157

Lisp - Increasing all elements by a number

It prints 1 on the screen even though I increased its value in the function. Is there a way to call the parameter by reference so I can use it after the function call?

    (defparameter a 1)
    (defun foo (x)
        (+ x 1))
    (foo a)
    (print a)

Upvotes: 2

Views: 384

Answers (2)

Gwang-Jin Kim
Gwang-Jin Kim

Reputation: 9865

General solution - destructive access to variable

I think, what you wanted to know is actually this:

(defparameter a 1)

(defmacro foo (x)
  `(setf ,x (+ ,x 1)))  ;; this macro takes the variable given for x
                        ;; accesses its memory location using `setf`
                        ;; and changes its value  to 2
                        ;; by increasing the accessed value by 1
(foo a)                 ;; a's value becomes 2 
a                       ;; 2

However, as a beginner in common lisp, be careful to mutate wildly values around. Although I don't want to take you the joy of the power of Lisp. :)

Special solution - foo = incf

But foo (which increments a given value by 1) is exactly incf in common lisp, because this increment by one is often needed. So for this very special case, you can just use incf.

(defparameter a 1)
a ;; => 1

(incf a)  ;; incf mutates a to 2 - in exactly the way foo does

a ;; => 2 ;; a ist after that changed.

Note, there is also decf which decrements the variable by 1 - the opposite of incf.

Secial solution for global variables

But for global variables, you can use very normal defparameter to reassign the value to a:

(defparameter a 1)

(defparameter a (foo a))  ;; reassigns new value `2` to `a`

a ;; returns 2, since mutated now

Comment to the very first version:

(setf <var> <new-value>) is like a pointer access to the variable's memory location and writing to it what is given for <new-value>. So in Lisp, you have to use a combination of defmacro and setf to imitate or actually do call-by-reference like in C or Python.

But you know from Python or C already, how un-anticipated side-effects call-by-reference can provoke. Python does by default call-by-reference due to performance reasons (because Python is interpreted and it would become very slow if doing call-by-value everytime a function is called). But with Lisp, you are/you can be at least whenever you want magnitudes faster than interpreted Python (Okay, I am simplifying - Python can of course call C function an be also super fast - however, pure Python of course would be by magnitudes slower than compiled Lisp). And you have many other possibilities to program the same thing. So don't try to imitate Python or other programs function call behaviour in Lisp - that is the wrong track.

Learn functional programming (FP) rules, which tries to not to mutate any values, but to do always call-by-value (like your function foo does). It produces 2 but leaves a the same. To reason about such programs is much more brain-friendly, thus can save you in many cases from avoidable bugs. FP is definitely sth you should learn, when dealing with Lisp btw. FP is amongst many other concepts sth what you learn when you learn Lisp - and I wouldn't want to miss it.

Destructive functions make only sense if state is really unavoidable and desired, and especially if performance is important.

Upvotes: 3

Kaz
Kaz

Reputation: 58578

Your code doesn't contain any traces of an operator that modifies a storage location in-place. Neither the variable a nor x are subject to mutation.

The function foo returns a number that is greater than the input number by 1.

Note that a and x are distinct variables; if we were to increment x, that has no effect on a.

Numbers are not mutable objects in ANSI Lisp; if we increment a variable x with (incf x) what is happening is that the value (+ 1 x) is calculated, and this new value stored back into the x variable.

ANSI Lisp function parameters use "pass by value", like most major Lisp dialects. When (foo a) is invoked, the argument expression a is reduced to a value: it produces the value 1. This value is no longer associated with the variable. It is passed into the function without any memory of having come from a. Inside the function, a new variable x is instantiated that is local to the function; this receives a copy of the argument value: it is initialized with 1. So x has nothing to do with a; it has just received the same value.

Upvotes: 6

Related Questions