How to globally change a variable value inside a function in lisp

I would like to know if there is a way to simulate C behavior with pointers in LISP. In C, if you change the value of the variable pointed to by this pointer, it has a global effect (i.e., the value will also be changed outside the function).

So, if I had

(defun mutate ( a ) 
   (some-magic-function a 5)
)

a will turn into 5 after calling the mutant, regardless of what happened before.

I know this is possible (as a side effect) with list items In general lisp, how do I change part of a list parameter from a function without changing the original list? but I would like to know how to do this for the whole list.

+2
source share
3

C

sds answer , , , C,

, C LISP. C, , , (.. ).

, , , Lisp, :

#include<stdio.h>

int a = 3;

int mutate( int a ) {
  return a = 5;
}

int main() { 
  mutate( a );         /* or mutate( 8 ) or anything other argument */
  printf( "%d\n", a ); /* prints 3 */
  return 0;
}

, a in mutate - , mutate. , a, , . , mutate variable a, mutate. " [] , [a]. , , , . C:

#include<stdio.h>

int a = 3;

int mutate( int *a ) {
  return (*a = 5);
}

int main() { 
  mutate( &a );
  printf( "%d\n", a ); /* prints 5 */
  return 0;
}

Common Lisp , , . , a a cons, car 3, cons car:

CL-USER> (defparameter *a* (cons 3 nil))
*A*
CL-USER> (defun mutate (cons)
           (setf (car cons) 5))
MUTATE
CL-USER> (mutate *a*)
5
CL-USER> (car *a*)
5

- Lisp, C, "" - , . Common Lisp, cons-, - , .

C-, Common Lisp , .

5.1.1

- , , , . - , . setf. Common Lisp, , .

Common Lisp setf. , sds , , , setf, symbol-value. (defparameter *a* 3) *a*, (symbol-value '*a*) , *a*. place value, , :

(defmacro mutate (place value)
  `(setf ,place ,value))

C

, , . , , C.

(defmacro make-pointer (place)
  `(lambda (op &optional value)
     (ecase op
       ((read)  ,place)
       ((write) (setf ,place value)))))

(let* ((x 3)
       (xp (make-pointer x)))
  (funcall xp 'write 5)             ; write a new value to x
  (list (funcall xp 'read)          ; read the value from x through xp
        x))                         ; read the value from x directly
;=> (5 5)

make-pointer , . read write, , write, . read, . write, .

. , , , (print 2) 2:

(make-pointer (aref some-array (print 2)))

2 , , , , . , , .

( , ?), , Lisp ( Lisp Machine Lisp, Common Lisp)) , C-, , Lisp, . , , , 13. Lisp reïmplementations Common Lisp, Alan Crowe's, , () :

;;; The basic idea is to use closures

( ), :

;;; It looks as though we are done
;;; now we can translate C code
;;; &x = (addr x), *x = (data x)

;;; The trouble is, we have a multiple evaluation bug.

Crowe , get-setf-expansion , , (print 2) . , , !

+8

, :

(defun mutate (symbol value)
  (setf (symbol-value symbol) value))
(mutate 'foo 42)
foo
==> 42

, symbol mutate .

(defmacro mutate (symbol value)
  `(setf ,symbol ,value))
(mutate foo 42)
foo
==> 42

symbol .

Lisp, , , , . , , (foo (! 5)), (foo 120), (foo x), 120 , (1- ), (2- ) (3- ).

( ), ( ). , , ( ).

+4

Lisp , " " , "" Lisp: , , ..

, , , C.

, (ref (foo-accessor (cdr (aref a 4))) , a, , cdr, foo-accessor .

, , .

:

(defun mutate-to-five (ptr)          |            void mutate_to_five(int *a)
  (setf (deref ptr) 5))              |            { *ptr = 5; }
                                     |
(defparameter a 42)                  |            int a = 42;
                                     |            /*...*/
(mutate-to-five (ref a))             |              mutate_to_five(&a);

, , , , C-. . - , , , . , . : , . , , , , , .

A Lisp - - . . , , , , - ( ). , , "" . Lisp , . . , " ?". , . ( , Linux, struct vmadescribing the virtual memory mapping that contains this address.)

Implementation:

;;;
;;; Lisp references: pointer-like place locators that can be passed around.
;;; Source: http://www.kylheku.com/cgit/lisp-snippets/plain/refs.lisp
;;; 
;;; How to use:
;;;
;;; Produce a reference which "lifts" the place designated
;;; by form P:
;;;
;;;   (ref p)
;;;
;;; Dereference a reference R to designate the original place:
;;;
;;;   (deref r)
;;;   (setf (deref r) 42) ;; store new value 42
;;;
;;; Shorthand notation instead of writing a lot of (deref)
;;; Over FORMS, A is a symbol macro which expands to 
;;; (DEREF RA), B expands to (DEREF RB):
;;;
;;;   (with-refs ((a ra) (b rb) ...)
;;;     
;;;     ... forms)
;;; 
(defstruct ref 
  (get-func) 
  (set-func))

(defun deref (ref) 
  (funcall (ref-get-func ref))) 

(defun (setf deref) (val ref) 
  (funcall (ref-set-func ref) val)) 

(defmacro ref (place-expression &environment env)
  (multiple-value-bind (temp-syms val-forms 
                        store-vars store-form access-form)
                        (get-setf-expansion place-expression env)
    (when (cdr store-vars)
      (error "REF: cannot take ref of multiple-value place"))
    `(multiple-value-bind (,@temp-syms) (values ,@val-forms)
       (make-ref
         :get-func (lambda () ,access-form)
         :set-func (lambda (,@store-vars) ,store-form)))))

(defmacro with-refs ((&rest ref-specs) &body forms) 
  `(symbol-macrolet 
     ,(loop for (var ref) in ref-specs 
            collecting (list var `(deref ,ref))) 
     ,@forms))
+1
source

Source: https://habr.com/ru/post/1543650/


All Articles