Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Variable references in lisp

Another newbie (Common) LISP question:

Basically in most programming languages there's a mean for functions to receive references to variables instead of just values, that is, passing by reference instead of passing by value. Let's say, for the sake of simplicity, I want to write a LISP function that receives a variable and increases the value of the variable by one:

(defun increase-by-one (var)   (setf var (+ var 1))) 

Now obviously the problem is that this function only increases the value of the copy of the variable on the stack, not the actual original variable. I've also tried to achieve the effect by using macros without much success, although I have this feeling that using macros is the right way to go.

I hit this wall all the time in LISP and I'm sure there must be a way around it or maybe there's a completely different approach to this problem in LISP I haven't thought about? How are things like this are done in LISP?

EDIT: Multiple people has suggested using incf. I only used this example to demonstrate the problem in a simple way, I wasn't actually looking for reimplementing incf. But thanks for the suggestions anyway.

like image 478
Tamas Czinege Avatar asked Aug 08 '09 21:08

Tamas Czinege


People also ask

Are there variables in Lisp?

LISP supports two types of variables: Local variables. Global variables.

Which types of variable are used in Lisp?

In LISP, variables are not typed, but data objects are. LISP data types can be categorized as. Scalar types − for example, number types, characters, symbols etc. Data structures − for example, lists, vectors, bit-vectors, and strings.

Is Lisp pass by reference?

You can produce similar effect by using return values, this is a possible design pattern in Lisp, even though it is not passing a variable by reference.

How do you define a variable in a Common Lisp?

Common Lisp provides two ways to create global variables: DEFVAR and DEFPARAMETER . Both forms take a variable name, an initial value, and an optional documentation string. After it has been DEFVAR ed or DEFPARAMETER ed, the name can be used anywhere to refer to the current binding of the global variable.


1 Answers

With lexical scope one does not have access to variables that are not in the current scope. You also cannot pass lexical variables to other functions directly. Lisp evaluates variables and passes the values bound to these variables. There is nothing like first-class references to variables.

Think functional!

(let ((a 1))   (values (lambda (new-value)             (setf a new-value))            (lambda () a))) 

above returns two functions. One can read the variable, another one can write the variable.

Let's call the first function writer and the second one reader.

(defun increase-by-one (writer reader)    (funcall writer (1+ (funcall reader)))) 

So, to do what you want, the code needs a) be in the scope or b) have access to functions that are in the scope.

Also the variable could be global.

(defvar *counter* 1)  (defun increase-by-one (symbol)   (set symbol (1+ (symbol-value symbol))))   ; note the use of SET to set a symbol value  (increase-by-one '*counter*) 

This works for global variables that are represented by a symbol. It does not work for lexical variables - these are not represented by a symbol.

There is also a macro INCF that increases a 'place' (for example a variable).

(incf a) 

But a is the variable in the current scope.

(defun foo (a)   (incf a))  ; increases the local variable a 

The limit is seen here:

(defun foo (var)   (add-one-some-how var))  (let ((a 1))    (foo something-referencing-a)) 

There is no way to pass a direct reference of a to FOO.

The only way is to provide a function. We also have to rewrite FOO, so that it calls the provided function.

(defun foo (f)   (funcall f 1))   ; calls the function with 1  (let ((a 1))    (foo (lambda (n)           (setf a (+ a n)))))    ;; passes a function to foo that can set a 
like image 64
Rainer Joswig Avatar answered Sep 28 '22 16:09

Rainer Joswig