From: Berk Birand
Subject: Change function parameter from inside the function
Date: 
Message-ID: <pan.2006.10.04.06.12.46.50888@yahoo.com>
Hi,

Is there a way to change a parameter to a function in the body of the
function? For instance, I have this function

(defun add-to-population (rs1 population)
    (adjoin rs1 population :test #'equal)
)

That I use this way
(setq current-population (add-to-population result current-population))

But since I always use this same form (return a value, and then use setq
to assign this return value to the function parameter), I would like to do
this operation this way:

(add-to-population result current-population)

Basically, whatever is passed as the population argument should be
assigned the result of the adjoin. How is this possible?

Thanks,
Berk Birand

-- 
Posted via a free Usenet account from http://www.teranews.com

From: Pascal Costanza
Subject: Re: Change function parameter from inside the function
Date: 
Message-ID: <4oh241Feg2otU1@individual.net>
Berk Birand wrote:
> Hi,
> 
> Is there a way to change a parameter to a function in the body of the
> function? For instance, I have this function
> 
> (defun add-to-population (rs1 population)
>     (adjoin rs1 population :test #'equal)
> )
> 
> That I use this way
> (setq current-population (add-to-population result current-population))
> 
> But since I always use this same form (return a value, and then use setq
> to assign this return value to the function parameter), I would like to do
> this operation this way:
> 
> (add-to-population result current-population)
> 
> Basically, whatever is passed as the population argument should be
> assigned the result of the adjoin. How is this possible?

Common Lisp doesn't have a way to pass parameters by reference. But you 
can write a macro, like this:

(defmacro push-to-population (result population)
   `(pushnew ,result ,population :test #'equal))


Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Berk Birand
Subject: Re: Change function parameter from inside the function
Date: 
Message-ID: <pan.2006.10.04.17.27.32.597143@yahoo.com>
On Wed, 04 Oct 2006 08:19:52 +0200, Pascal Costanza wrote:

> 
> Common Lisp doesn't have a way to pass parameters by reference. But you 
> can write a macro, like this:
> 
> (defmacro push-to-population (result population)
>    `(pushnew ,result ,population :test #'equal))

Is there any reason why you would use a macro in this case? It seems like
the key is to use pushnew instead of adjoin, so this exact macro could be
defined as a function, and do the same thing right?

I knew macros from Scheme, but I'm kind of startled by the way things work
in LISP, which seems quite different.

Thanks for the answer,
Berk

-- 
Posted via a free Usenet account from http://www.teranews.com
From: Rahul Jain
Subject: Re: Change function parameter from inside the function
Date: 
Message-ID: <87ejtnop39.fsf@nyct.net>
Berk Birand <········@yahoo.com> writes:

> Is there any reason why you would use a macro in this case? It seems like
> the key is to use pushnew instead of adjoin, so this exact macro could be
> defined as a function, and do the same thing right?

No, because the result of a push could be a new object. The calling
function wouldn't know about that object.

-- 
Rahul Jain
·····@nyct.net
Professional Software Developer, Amateur Quantum Mechanicist
From: Lars Rune Nøstdal
Subject: Re: Change function parameter from inside the function
Date: 
Message-ID: <pan.2006.10.04.18.45.45.907636@gmail.com>
On Wed, 04 Oct 2006 13:27:32 -0400, Berk Birand wrote:

> On Wed, 04 Oct 2006 08:19:52 +0200, Pascal Costanza wrote:
> 
>> 
>> Common Lisp doesn't have a way to pass parameters by reference. But you 
>> can write a macro, like this:
>> 
>> (defmacro push-to-population (result population)
>>    `(pushnew ,result ,population :test #'equal))
> 
> Is there any reason why you would use a macro in this case? It seems like
> the key is to use pushnew instead of adjoin, so this exact macro could be
> defined as a function, and do the same thing right?
> 
> I knew macros from Scheme, but I'm kind of startled by the way things work
> in LISP, which seems quite different.

http://www.lisperati.com/different.jpg :)

-- 
Lars Rune Nøstdal
http://lars.nostdal.org/
From: Berk Birand
Subject: Re: Change function parameter from inside the function
Date: 
Message-ID: <pan.2006.10.04.19.01.32.825174@yahoo.com>
On Wed, 04 Oct 2006 20:45:47 +0200, Lars Rune N�stdal wrote:

>> 
>> I knew macros from Scheme, but I'm kind of startled by the way things work
>> in LISP, which seems quite different.
> 
> http://www.lisperati.com/different.jpg :)

I meant compared to Scheme though. So difference is not that *as* big as
the one between C#, VB etc...

-- 
Posted via a free Usenet account from http://www.teranews.com
From: Lars Rune Nøstdal
Subject: Re: Change function parameter from inside the function
Date: 
Message-ID: <pan.2006.10.04.19.31.10.882941@gmail.com>
On Wed, 04 Oct 2006 13:27:32 -0400, Berk Birand wrote:

> On Wed, 04 Oct 2006 08:19:52 +0200, Pascal Costanza wrote:
> 
>> 
>> Common Lisp doesn't have a way to pass parameters by reference. But you 
>> can write a macro, like this:
>> 
>> (defmacro push-to-population (result population)
>>    `(pushnew ,result ,population :test #'equal))
> 
> Is there any reason why you would use a macro in this case? It seems like
> the key is to use pushnew instead of adjoin, so this exact macro could be
> defined as a function, and do the same thing right?

(to answer your question about adjoin/pushnew)
Nope:

cl-user> (let ((population '(:a :b :c)))
           (adjoin :x population :test #'equal)
           population)
(:a :b :c)
cl-user> (let ((population '(:a :b :c)))
           (pushnew :x population :test #'equal)
           population)
(:x :a :b :c)
cl-user> 

If I macroexpand the `pushnew' call/macro (you can do this in Slime
with C-c <enter> btw.):

cl-user> (macroexpand-1 '(pushnew :x population :test #'equal))
(let* ((#:g1856 :x) (#:g1855 (adjoin #:g1856 population :test #'equal)))
  (setq population #:g1855))

..and..

cl-user> (let ((population '(:a :b :c)))
           (let ((population population))
             ;; Inside your function `add-to-population'.
             (setq population "Only effects inside `population'!")
             (format t "`population' inside `add-to-population': '~A'~%" population))
           population)
`population' inside `add-to-population': 'Only effects inside `population'!'
(:a :b :c)

Which means setf/setq works on the _innermost binding_ of what
`population' _points to_:

cl-user> (let ((population "outher"))
           (let ((population "inner"))
             (setf population "only affects what _inner_ `population' _points to_"))
           population)

"outher"


(now let's see if I got this stuff right .. lol)

-- 
Lars Rune Nøstdal
http://lars.nostdal.org/
From: Pascal Costanza
Subject: Re: Change function parameter from inside the function
Date: 
Message-ID: <4okk33Fep3bfU2@individual.net>
Berk Birand wrote:
> On Wed, 04 Oct 2006 08:19:52 +0200, Pascal Costanza wrote:
> 
>> Common Lisp doesn't have a way to pass parameters by reference. But you 
>> can write a macro, like this:
>>
>> (defmacro push-to-population (result population)
>>    `(pushnew ,result ,population :test #'equal))
> 
> Is there any reason why you would use a macro in this case? It seems like
> the key is to use pushnew instead of adjoin, so this exact macro could be
> defined as a function, and do the same thing right?
> 
> I knew macros from Scheme, but I'm kind of startled by the way things work
> in LISP, which seems quite different.

You cannot have side effects on variables that you pass to functions, 
neither in Common Lisp nor in Scheme, because both do not provide call 
by reference.

That's why macros are the only way to build abstractions that perform 
side effects on variables, again both in Common Lisp and in Scheme.

It's important to note that I have said "side effects on variables" in 
both cases. It is indeed possible to write functions that have side 
effects on components in data structures. That's an important 
difference: Variables and the data structures the refer to!


Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Lars Rune Nøstdal
Subject: Re: Change function parameter from inside the function
Date: 
Message-ID: <pan.2006.10.05.16.13.15.512828@gmail.com>
On Thu, 05 Oct 2006 16:44:52 +0200, Pascal Costanza wrote:
> It's important to note that I have said "side effects on variables" in 
> both cases. It is indeed possible to write functions that have side 
> effects on components in data structures. That's an important 
> difference: Variables and the data structures the refer to!

This means that this does work:

cl-user> (let ((population "outher"))
           (let ((population population))
             (setf (char population 0) #\x))
           population)
"xuther"


Note that SBCL gives a warning about changing constant data here:

cl-user> (dotimes (i 2)
           (let ((population "outher"))
             (format t "population before: ~A~%" population)
             (let ((population population))
               (setf (char population 0) #\x))
             (format t "population after: ~A~%" population)))

population before: outher
population after: xuther
population before: xuther
population after: xuther

..this can be solved by making a copy of the original constant string
using `copy-seq'. I believe this can be (mis?)used for creating code
that changes itself - but I'm not too sure about this. :)

-- 
Lars Rune Nøstdal
http://lars.nostdal.org/
From: Rahul Jain
Subject: Re: Change function parameter from inside the function
Date: 
Message-ID: <87hcyilc3c.fsf@nyct.net>
Lars Rune N�stdal <···········@gmail.com> writes:

> ..this can be solved by making a copy of the original constant string
> using `copy-seq'. I believe this can be (mis?)used for creating code
> that changes itself - but I'm not too sure about this. :)

Yes, literals are typically considered to be "part of the code" so
modifying a literal would be modifying the code. The next time you ran
it, it wouldn't be running the same thing that you originally typed.

-- 
Rahul Jain
·····@nyct.net
Professional Software Developer, Amateur Quantum Mechanicist
From: Pascal Costanza
Subject: Re: Change function parameter from inside the function
Date: 
Message-ID: <4okqgjFf98c8U3@individual.net>
Lars Rune Nøstdal wrote:
> On Thu, 05 Oct 2006 16:44:52 +0200, Pascal Costanza wrote:
>> It's important to note that I have said "side effects on variables" in 
>> both cases. It is indeed possible to write functions that have side 
>> effects on components in data structures. That's an important 
>> difference: Variables and the data structures the refer to!
> 
> This means that this does work:
> 
> cl-user> (let ((population "outher"))
>            (let ((population population))
>              (setf (char population 0) #\x))
>            population)
> "xuther"
> 
> 
> Note that SBCL gives a warning about changing constant data here:
> 
> cl-user> (dotimes (i 2)
>            (let ((population "outher"))
>              (format t "population before: ~A~%" population)
>              (let ((population population))
>                (setf (char population 0) #\x))
>              (format t "population after: ~A~%" population)))
> 
> population before: outher
> population after: xuther
> population before: xuther
> population after: xuther
> 
> ..this can be solved by making a copy of the original constant string
> using `copy-seq'. I believe this can be (mis?)used for creating code
> that changes itself - but I'm not too sure about this. :)

ANSI CL forbids side effects on literal data, including strings and 
quoted objects.

Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Alan Crowe
Subject: Re: Change function parameter from inside the function
Date: 
Message-ID: <86ven03r86.fsf@cawtech.freeserve.co.uk>
Berk Birand <········@yahoo.com> writes:
> Is there a way to change a parameter to a function in the body of the
> function? For instance, I have this function
> 
> (defun add-to-population (rs1 population)
>     (adjoin rs1 population :test #'equal)
> )
> 
> That I use this way
> (setq current-population (add-to-population result current-population))
> 
> But since I always use this same form (return a value, and then use setq
> to assign this return value to the function parameter), I would like to do
> this operation this way:
> 
> (add-to-population result current-population)
> 
> Basically, whatever is passed as the population argument should be
> assigned the result of the adjoin. How is this possible?

If you may swap the argument that gets assigned to to the
front of the argument list

CL-USER> (defun add-to-pop (population new-member)
           (adjoin new-member population :test #'equal))

you can then use

CL-USER> (define-modify-macro add-to-pop-f (new-member) add-to-pop)
ADD-TO-POP-F

to get CL to write a modify macro for you.

Then you can use it

CL-USER> (defparameter *a* (make-array 10 :initial-element nil))
*A*
CL-USER> (add-to-pop-f (aref *a* (print 3)) 'one)

3 

(ONE)
CL-USER> (add-to-pop-f (aref *a* (print 3)) 'one)

3 

(ONE)
CL-USER> (add-to-pop-f (aref *a* (print 3)) 'two)

3 

(TWO ONE)
CL-USER> (add-to-pop-f (aref *a* (print 3)) 'three)

3 

(THREE TWO ONE)
CL-USER> (add-to-pop-f (aref *a* (print 3)) 'two)

3 

(THREE TWO ONE)

You could bodge your own modify macro like this

CL-USER> (defmacro add-to-pop-f (place new-value)
           `(setf ,place (add-to-pop ,place ,new-value)))
ADD-TO-POP-F

but notice that it duplicates the place code so the place
code gets run twice

CL-USER> (add-to-pop-f (aref *a* (print 3)) 'two)

3 
3 

(THREE TWO ONE)

If you use define-modify-macro it writes the macro properly
using get-setf-expansion so that subforms of the place are
only evaluated once. After restoring the original definition

CL-USER> (macroexpand-1 '(add-to-pop-f (aref *a* (print 3)) 'two))
(LET* ((#:G1607 *A*)
       (#:G1606 (PRINT 3))
       (#:G1605 (ADD-TO-POP (AREF #:G1607 #:G1606) 'TWO)))
  (LISP::%ASET #:G1607 #:G1606 #:G1605))

Usually the place is just a variable, so this doesn't
matter, but if you use define-modify-macro (or
get-setf-expansion) CL lets you write things such as

(add-to-pop-f (aref *a* (incf i)) 'two)

and it works right (i is only incremented once).



Alan Crowe
Edinburgh
Scotland