From: Jimka
Subject: a += b    a ||= b
Date: 
Message-ID: <1143408242.703871.272490@t31g2000cwb.googlegroups.com>
I would like to write a macro around setf which immitates the
functionality of the op= operators like found in c and perl.  It is
easy to
do but i do not know what to call the macro.    Does such a macro
already have a standard name?

It will look something like the following:

(defmacro updatef (args)
  (destructuring-bind (function place &rest values) args
    `(setf ,place (,function ,place ,@values))))

So a += b             becomes (updatef (plus a b))
     a ||= b || c || d   becomes (updatef (or a b c d))

Perhaps the macro could also eliminate the need for the redundant
parentheses???

But what is a good name for the macro?

From: André Thieme
Subject: Re: a += b a ||= b
Date: 
Message-ID: <1143413846.075844.9810@t31g2000cwb.googlegroups.com>
Jimka schrieb:

> I would like to write a macro around setf which immitates the
> functionality of the op= operators like found in c and perl.  It is
> easy to
> do but i do not know what to call the macro.    Does such a macro
> already have a standard name?
>
> It will look something like the following:
>
> (defmacro updatef (args)
>   (destructuring-bind (function place &rest values) args
>     `(setf ,place (,function ,place ,@values))))
>
> So a += b             becomes (updatef (plus a b))
>      a ||= b || c || d   becomes (updatef (or a b c d))
>
> Perhaps the macro could also eliminate the need for the redundant
> parentheses???
>
> But what is a good name for the macro?

At least += and -= already have good names:
(infc a b)
(decf a b)


André
--
From: ····@unreal.uncom
Subject: Re: a += b    a ||= b
Date: 
Message-ID: <fdge2294haaiq2ngqdi1bp7d1e6kv1gqp8@4ax.com>
On 26 Mar 2006 13:24:02 -0800, "Jimka" <·····@rdrop.com> wrote:

>do but i do not know what to call the macro.    Does such a macro
>already have a standard name?

Look in the hyperspec for define-modify-macro.

Assuming the goal is to easily define a large number of *f macros,
similar to setf, incf, etc., you could write a macro that takes
function names as its arguments and creates the *f macro for each, by
invoking define-modify-macro for each.

E.g.

(define-f-macros min max nreverse)

would define minf, maxf, and nreversef.

Of course define-f-macros would have to derive the symbol names of
minf etc. from min etc., but that's easy in lisp.
From: Kaz Kylheku
Subject: Re: a += b a ||= b
Date: 
Message-ID: <1143441648.018801.274660@t31g2000cwb.googlegroups.com>
Jimka wrote:
> It will look something like the following:
>
> (defmacro updatef (args)
>   (destructuring-bind (function place &rest values) args
>     `(setf ,place (,function ,place ,@values))))
>
> So a += b             becomes (updatef (plus a b))

This is called (INCF A B).  The default increment is 1 if you leave it
out.

>      a ||= b || c || d   becomes (updatef (or a b c d))

There is no ||= operator in C. It's not useful.

In fifteen years, I've written code like this, I think, exactly twice.

   flag = condition;
   /*...*/
   flag = flag && additional_condition;

It's not worth having a dedicated operator to express this.
From: Jimka
Subject: Re: a += b a ||= b
Date: 
Message-ID: <1143577938.919498.86160@i39g2000cwa.googlegroups.com>
>There is no ||= operator in C. It's not useful.
>
>In fifteen years, I've written code like this, I think, exactly twice.

Are you making a joke?  I"m not sure if this silly comment was intended
to be
humerous.    I have not programmed in C for many years but often
when i'm forced to program in perl i want to use the ||= operator and
cannot.

$ENV{'DEBUG'} ||= 1;

this ought to set an env var if it is not already set.

The point is not that flag = flag && additional_condition would be more
useful,
the point is that if you have a complicated expression on the right and
left side
it would be nice to only have to type it once.  this is why incf and
decf are useful.

in c you might like to do something like *abcde[*fghij->cklmno] += 1;
similarly you might want to *abcde[*fghij->cklmno]  *=2;
or *abcde[*fghij->cklmno]  &&= TRUE;

Do not confuse a limitation of a your programming language with
your inability to generalize.
From: Kaz Kylheku
Subject: Re: a += b a ||= b
Date: 
Message-ID: <1143586444.337518.88410@i39g2000cwa.googlegroups.com>
Jimka wrote:
> >There is no ||= operator in C. It's not useful.
> >
> >In fifteen years, I've written code like this, I think, exactly twice.
>
> Are you making a joke?  I"m not sure if this silly comment was intended
> to be
> humerous.    I have not programmed in C for many years but often
> when i'm forced to program in perl i want to use the ||= operator and
> cannot.
>
> $ENV{'DEBUG'} ||= 1;
>
> this ought to set an env var if it is not already set.

It's pointless to set something if it isn't already set. You just set
it:

$ENV{'DEBUG'} = 1;

Oh, but the variable isn't boolean because it has three or more states?

Then you shouldn't be treating it with a boolean operator.

Environment variables are strings which may or may not exist. When they
exist, they might contain all kinds of garbage, which serves as an
input to your software and has to be validated. You should have a
separate debug variable, with a well-defined default value.

Then you have logic like:

  if (debug environment variable exists)
    parse value from environment variable
    handle garbage value situations
    override debug variable using parsed value

Of course, when people are writing Perl code, it's usually throwaway
stuff for their own personal use.

> or *abcde[*fghij->cklmno]  &&= TRUE;

*abcde[*fghij->cklmno]  = TRUE; /* Doh! */

Let me clue you in a little bit here. You see where this would be
useful is when you have a non-trivial expression on the right, which
you might or might not want to evaluate based on the existing value of
the place.

You are combining three elements: fetching a place, conditionally
evaluating an expression based on the old value of the place to compute
a new value, which goes into that place without having to fetch that
place again.

> Do not confuse a limitation of a your programming language with
> your inability to generalize.

What if I want to test the existing value of the place in different
ways? What if I want to involve two or more places in a single
transaction?

What you want is some powerful construct like

 (update
   place a = (gethash key hash)
   place b = (aref x y)
   by
      (unless (> (some-function a b) 42)
        (psetf
          a (some-other-function a b)
          b (some-third-function a b))))

What this would do is establish A and B as representing these two
places, and then execute the body of the update. Somehow, within that
body, A and B would not just be naive symbol-macrolets for these
places, but expand to expressions that use the existing pre-fetched
places.

Who is unable to generalize?
From: Kalle Olavi Niemitalo
Subject: Re: a += b a ||= b
Date: 
Message-ID: <87acb96nc7.fsf@Astalo.kon.iki.fi>
"Kaz Kylheku" <········@gmail.com> writes:

> Somehow, within that body, A and B would not just be naive
> symbol-macrolets for these places, but expand to expressions
> that use the existing pre-fetched places.

I posted such a macro a year ago: <···················@Astalo.kon.iki.fi>
It had a simpler syntax though.

>  (update
>    place a = (gethash key hash)
>    place b = (aref x y)
>    by
>       (unless (> (some-function a b) 42)
>         (psetf
>           a (some-other-function a b)
>           b (some-third-function a b))))

  (symbol-macroletf
      ((a (gethash key hash))
       (b (aref x y)))
    (unless (> (some-function a b) 42)
      (psetf
        a (some-other-function a b)
        b (some-third-function a b))))
From: Wade Humeniuk
Subject: Re: a += b    a ||= b
Date: 
Message-ID: <cvFVf.12521$%H.321@clgrps13>
Jimka wrote:
> I would like to write a macro around setf which immitates the
> functionality of the op= operators like found in c and perl.  It is
> easy to
> do but i do not know what to call the macro.    Does such a macro
> already have a standard name?
> 
> It will look something like the following:
> 
> (defmacro updatef (args)
>   (destructuring-bind (function place &rest values) args
>     `(setf ,place (,function ,place ,@values))))
> 
> So a += b             becomes (updatef (plus a b))
>      a ||= b || c || d   becomes (updatef (or a b c d))
> 
> Perhaps the macro could also eliminate the need for the redundant
> parentheses???
> 
> But what is a good name for the macro?
> 

I suggest insetf or mirroring prog1, progn

(defmacro insetf1 (form)
   `(setf ,(cadr form) ,form))

(defmacro insetfn (form)
   `(setf ,(nth (1- (length form)) form) ,form))
CL-USER 13 > (defvar n 10)
N

CL-USER 14 > (insetf1 (+ n 20 30))
60

CL-USER 15 > n
60

CL-USER 16 > (insetfn (< 20 n))
T

CL-USER 17 > n
T

CL-USER 18 >
From: Frank Buss
Subject: Re: a += b    a ||= b
Date: 
Message-ID: <1a7qkss55co9q.4vwgpw0xefkp.dlg@40tude.net>
Jimka wrote:

> I would like to write a macro around setf which immitates the
> functionality of the op= operators like found in c and perl.  It is
> easy to
> do but i do not know what to call the macro.    Does such a macro
> already have a standard name?

what about += ?

(defmacro += (variable &rest rest)
  `(setf ,variable (+ ,variable ,@rest)))

CL-USER > (macroexpand-1 '(+= a b c))
(SETF A (+ A B C))

-- 
Frank Buss, ··@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
From: Jimka
Subject: Re: a += b a ||= b
Date: 
Message-ID: <1143409260.245320.319240@z34g2000cwc.googlegroups.com>
no this is the macro which builds +=, and *= and ||= and max=

(setf a (max a b c d))
(setf a (* a b c d))
(setf a (xor a b c d))

etc....
From: Frank Buss
Subject: Re: a += b a ||= b
Date: 
Message-ID: <1f72xk8kc8ljv$.k2eyapgb79fm.dlg@40tude.net>
Jimka wrote:

> no this is the macro which builds +=, and *= and ||= and max=
> 
> (setf a (max a b c d))
> (setf a (* a b c d))
> (setf a (xor a b c d))

I don't understand what you mean. Your first macro looked like this:

(defmacro updatef (args)
  (destructuring-bind (function place &rest values) args
    `(setf ,place (,function ,place ,@values))))

This can be used like this:

CL-USER > (macroexpand-1 '(updatef (+ a b c d)))
(SETF A (+ A B C D))

I proposed a simpler version, where you don't need to specify the function:

(defmacro += (variable &rest rest)
  `(setf ,variable (+ ,variable ,@rest)))

which can be used like this:

CL-USER > (macroexpand-1 '(+= a b c d))
(SETF A (+ A B C D))

If you have to specify the function to use, it is not shorter than writing
it the normal way:

(updatef (+ a b c d)
(setf a (+ a b c d))

I think it is not very useful to use something like += or updatef, because
it hides what you are doing. If you have lots of operators like += or ||= I
think it is possible to write it simpler. But if you really need it, you
can write a macro, which writes all those macros for you :-)

-- 
Frank Buss, ··@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
From: Alexander Schmolck
Subject: Re: a += b    a ||= b
Date: 
Message-ID: <yfsy7ywakrx.fsf@oc.ex.ac.uk>
"Jimka" <·····@rdrop.com> writes:

> I would like to write a macro around setf which immitates the
> functionality of the op= operators like found in c and perl.  It is
> easy to
> do but i do not know what to call the macro.    Does such a macro
> already have a standard name?
> 
> It will look something like the following:
> 
> (defmacro updatef (args)
>   (destructuring-bind (function place &rest values) args
>     `(setf ,place (,function ,place ,@values))))
> 
> So a += b             becomes (updatef (plus a b))
>      a ||= b || c || d   becomes (updatef (or a b c d))
> 
> Perhaps the macro could also eliminate the need for the redundant
> parentheses???
> 
> But what is a good name for the macro?

If you don't fear syntactic sugar, how about:

(! a <-(+)- b)
(! a <-(or)- b c d)

or slightly easier:

(! a <=(+)= b)
(! a <=(or)= b c d)

(defmacro ! (place <= (f) = &rest values)
  (assert (and (eq <= '<=) (eq = '=)))
  `(updatef ,place (,f ,@values)))

For the first variant you'd need to export <- (or check for string-identity
instead of eq'ness just as loop does).

'as
From: Tobias C. Rittweiler
Subject: Re: a += b    a ||= b
Date: 
Message-ID: <873bh4kfby.fsf@GNUlot.localnet>
"Jimka" <·····@rdrop.com> writes:

> I would like to write a macro around setf which immitates the
> functionality of the op= operators like found in c and perl.  It is
> easy to do but i do not know what to call the macro.  Does such a
> macro already have a standard name?
>
> It will look something like the following:
>
> (defmacro updatef (args)
>   (destructuring-bind (function place &rest values) args
>     `(setf ,place (,function ,place ,@values))))

(You're evaluating PLACE twice. Also, why don't you destructure by the
macro lambda list directly?)

> So a += b             becomes (updatef (plus a b))
>    a ||= b || c || d  becomes (updatef (or a b c d))
>
> Perhaps the macro could also eliminate the need for the redundant
> parentheses???
>
> But what is a good name for the macro?

How about OP=, OPSETF or, for the pun, err, fun of it, OPDATEF?

  -T.
From: Ken Tilton
Subject: Re: a += b    a ||= b
Date: 
Message-ID: <iiFVf.60$8t7.11@fe11.lga>
Tobias C. Rittweiler wrote:
> "Jimka" <·····@rdrop.com> writes:
> 
> 
>>I would like to write a macro around setf which immitates the
>>functionality of the op= operators like found in c and perl.  It is
>>easy to do but i do not know what to call the macro.  Does such a
>>macro already have a standard name?
>>
>>It will look something like the following:
>>
>>(defmacro updatef (args)
>>  (destructuring-bind (function place &rest values) args
>>    `(setf ,place (,function ,place ,@values))))
> 
> 
> (You're evaluating PLACE twice. Also, why don't you destructure by the
> macro lambda list directly?)

No, he reads it once and setf's it once.

ken

-- 
Cells: http://common-lisp.net/project/cells/

"And I will know my song well before I start singing."  - Bob Dylan
From: Pascal Bourguignon
Subject: Re: a += b    a ||= b
Date: 
Message-ID: <873bh4kczu.fsf@thalassa.informatimago.com>
Ken Tilton <·········@gmail.com> writes:

> Tobias C. Rittweiler wrote:
>> "Jimka" <·····@rdrop.com> writes:
>> 
>>>I would like to write a macro around setf which immitates the
>>>functionality of the op= operators like found in c and perl.  It is
>>>easy to do but i do not know what to call the macro.  Does such a
>>>macro already have a standard name?
>>>
>>>It will look something like the following:
>>>
>>>(defmacro updatef (args)
>>>  (destructuring-bind (function place &rest values) args
>>>    `(setf ,place (,function ,place ,@values))))
>> (You're evaluating PLACE twice. Also, why don't you destructure by
>> the
>> macro lambda list directly?)
>
> No, he reads it once and setf's it once.

Really, Ken!

[8]> (defmacro updatef (args)
  (destructuring-bind (function place &rest values) args
    `(setf ,place (,function ,place ,@values))))

UPDATEF
[9]> (macroexpand-1 '(updatef (+ (aref a (incf i)) 2)))
(SETF (AREF A (INCF I)) (+ (AREF A (INCF I)) 2)) ;
T

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

ATTENTION: Despite any other listing of product contents found
herein, the consumer is advised that, in actuality, this product
consists of 99.9999999999% empty space.
From: Ken Tilton
Subject: Re: a += b    a ||= b
Date: 
Message-ID: <2UHVf.2023$sU4.1526@fe12.lga>
Pascal Bourguignon wrote:
> Ken Tilton <·········@gmail.com> writes:
> 
> 
>>Tobias C. Rittweiler wrote:
>>
>>>"Jimka" <·····@rdrop.com> writes:
>>>
>>>
>>>>I would like to write a macro around setf which immitates the
>>>>functionality of the op= operators like found in c and perl.  It is
>>>>easy to do but i do not know what to call the macro.  Does such a
>>>>macro already have a standard name?
>>>>
>>>>It will look something like the following:
>>>>
>>>>(defmacro updatef (args)
>>>> (destructuring-bind (function place &rest values) args
>>>>   `(setf ,place (,function ,place ,@values))))
>>>
>>>(You're evaluating PLACE twice. Also, why don't you destructure by
>>>the
>>>macro lambda list directly?)
>>
>>No, he reads it once and setf's it once.
> 
> 
> Really, Ken!
> 
> [8]> (defmacro updatef (args)
>   (destructuring-bind (function place &rest values) args
>     `(setf ,place (,function ,place ,@values))))
> 
> UPDATEF
> [9]> (macroexpand-1 '(updatef (+ (aref a (incf i)) 2)))
> (SETF (AREF A (INCF I)) (+ (AREF A (INCF I)) 2)) ;
> T
> 

Looks like your setf'ing a number there, pascal. :)

ken

-- 
Cells: http://common-lisp.net/project/cells/

"And I will know my song well before I start singing."  - Bob Dylan
From: Ken Tilton
Subject: Re: a += b    a ||= b
Date: 
Message-ID: <y8IVf.82$8t7.7@fe11.lga>
Pascal Bourguignon wrote:
> Ken Tilton <·········@gmail.com> writes:
> 
> 
>>Tobias C. Rittweiler wrote:
>>
>>>"Jimka" <·····@rdrop.com> writes:
>>>
>>>
>>>>I would like to write a macro around setf which immitates the
>>>>functionality of the op= operators like found in c and perl.  It is
>>>>easy to do but i do not know what to call the macro.  Does such a
>>>>macro already have a standard name?
>>>>
>>>>It will look something like the following:
>>>>
>>>>(defmacro updatef (args)
>>>> (destructuring-bind (function place &rest values) args
>>>>   `(setf ,place (,function ,place ,@values))))
>>>
>>>(You're evaluating PLACE twice. Also, why don't you destructure by
>>>the
>>>macro lambda list directly?)
>>
>>No, he reads it once and setf's it once.
> 
> 
> Really, Ken!
> 
> [8]> (defmacro updatef (args)
>   (destructuring-bind (function place &rest values) args
>     `(setf ,place (,function ,place ,@values))))
> 
> UPDATEF
> [9]> (macroexpand-1 '(updatef (+ (aref a (incf i)) 2)))
> (SETF (AREF A (INCF I)) (+ (AREF A (INCF I)) 2)) ;
> T
> 

What's your point? (Checkmate in two.)

:)

ken

-- 
Cells: http://common-lisp.net/project/cells/

"And I will know my song well before I start singing."  - Bob Dylan
From: Pascal Bourguignon
Subject: Re: a += b    a ||= b
Date: 
Message-ID: <87r74oip12.fsf@thalassa.informatimago.com>
Ken Tilton <·········@gmail.com> writes:
>>>No, he reads it once and setf's it once.
>> Really, Ken!
>> [8]> (defmacro updatef (args)
>>   (destructuring-bind (function place &rest values) args
>>     `(setf ,place (,function ,place ,@values))))
>> UPDATEF
>> [9]> (macroexpand-1 '(updatef (+ (aref a (incf i)) 2)))
>> (SETF (AREF A (INCF I)) (+ (AREF A (INCF I)) 2)) ;
>> T
>> 
>
> What's your point? (Checkmate in two.)

The point is that when you refer a place, the side effects should be
evaluated only once.

(setf       (aref a (incf i)) 1)  ; increments i once
(updatef (+ (aref a (incf i)) 1)) ; increments i twice

Of course, you can specify updatef otherwise, but then you should call
it:  updatef/double-side-effects

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

ADVISORY: There is an extremely small but nonzero chance that,
through a process known as "tunneling," this product may
spontaneously disappear from its present location and reappear at
any random place in the universe, including your neighbor's
domicile. The manufacturer will not be responsible for any damages
or inconveniences that may result.
From: Ken Tilton
Subject: Re: a += b    a ||= b
Date: 
Message-ID: <juIVf.235$YH5.72@fe10.lga>
Pascal Bourguignon wrote:
> Ken Tilton <·········@gmail.com> writes:
> 
>>>>No, he reads it once and setf's it once.
>>>
>>>Really, Ken!
>>>[8]> (defmacro updatef (args)
>>>  (destructuring-bind (function place &rest values) args
>>>    `(setf ,place (,function ,place ,@values))))
>>>UPDATEF
>>>[9]> (macroexpand-1 '(updatef (+ (aref a (incf i)) 2)))
>>>(SETF (AREF A (INCF I)) (+ (AREF A (INCF I)) 2)) ;
>>>T
>>>
>>
>>What's your point? (Checkmate in two.)
> 
> 
> The point is that when you refer a place, the side effects should be
> evaluated only once.
> 
> (setf       (aref a (incf i)) 1)  ; increments i once
> (updatef (+ (aref a (incf i)) 1)) ; increments i twice
> 
> Of course, you can specify updatef otherwise, but then you should call
> it:  updatef/double-side-effects
> 

Fine. So how do you fix updatef? With a gensym? (Mate in one. <g>)

kt

-- 
Cells: http://common-lisp.net/project/cells/

"And I will know my song well before I start singing."  - Bob Dylan
From: Pascal Bourguignon
Subject: Re: a += b    a ||= b
Date: 
Message-ID: <87fyl4ike1.fsf@thalassa.informatimago.com>
Ken Tilton <·········@gmail.com> writes:

> Fine. So how do you fix updatef? With a gensym? (Mate in one. <g>)

DEFINE-SETF-EXPANDER

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

HEALTH WARNING: Care should be taken when lifting this product,
since its mass, and thus its weight, is dependent on its velocity
relative to the user.
From: Pascal Bourguignon
Subject: Re: a += b    a ||= b
Date: 
Message-ID: <87acbcik2h.fsf@thalassa.informatimago.com>
Ken Tilton <·········@gmail.com> writes:

> Pascal Bourguignon wrote:
>> Ken Tilton <·········@gmail.com> writes:
>> 
>>>>>No, he reads it once and setf's it once.
>>>>
>>>>Really, Ken!
>>>>[8]> (defmacro updatef (args)
>>>>  (destructuring-bind (function place &rest values) args
>>>>    `(setf ,place (,function ,place ,@values))))
>>>>UPDATEF
>>>>[9]> (macroexpand-1 '(updatef (+ (aref a (incf i)) 2)))
>>>>(SETF (AREF A (INCF I)) (+ (AREF A (INCF I)) 2)) ;
>>>>T
>>>>
>>>
>>>What's your point? (Checkmate in two.)
>> The point is that when you refer a place, the side effects should be
>> evaluated only once.
>> (setf       (aref a (incf i)) 1)  ; increments i once
>> (updatef (+ (aref a (incf i)) 1)) ; increments i twice
>> Of course, you can specify updatef otherwise, but then you should
>> call
>> it:  updatef/double-side-effects
>> 
>
> Fine. So how do you fix updatef? With a gensym? (Mate in one. <g>)

With GET-SETF-EXPANSION.

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

"Debugging?  Klingons do not debug! Our software does not coddle the
weak."
From: Pascal Bourguignon
Subject: Re: a += b    a ||= b
Date: 
Message-ID: <8764m0ijgc.fsf@thalassa.informatimago.com>
Pascal Bourguignon <······@informatimago.com> writes:

> Ken Tilton <·········@gmail.com> writes:
>
>> Pascal Bourguignon wrote:
>>> Ken Tilton <·········@gmail.com> writes:
>>> 
>>>>>>No, he reads it once and setf's it once.
>>>>>
>>>>>Really, Ken!
>>>>>[8]> (defmacro updatef (args)
>>>>>  (destructuring-bind (function place &rest values) args
>>>>>    `(setf ,place (,function ,place ,@values))))
>>>>>UPDATEF
>>>>>[9]> (macroexpand-1 '(updatef (+ (aref a (incf i)) 2)))
>>>>>(SETF (AREF A (INCF I)) (+ (AREF A (INCF I)) 2)) ;
>>>>>T
>>>>>
>>>>
>>>>What's your point? (Checkmate in two.)
>>> The point is that when you refer a place, the side effects should be
>>> evaluated only once.
>>> (setf       (aref a (incf i)) 1)  ; increments i once
>>> (updatef (+ (aref a (incf i)) 1)) ; increments i twice
>>> Of course, you can specify updatef otherwise, but then you should
>>> call
>>> it:  updatef/double-side-effects
>>> 
>>
>> Fine. So how do you fix updatef? With a gensym? (Mate in one. <g>)
>
> With GET-SETF-EXPANSION.

Ok, no time to wait for your mate.
It's even easy:

(defmacro updatef ((function place &rest values) &environment env)
  (multiple-value-bind (vars vals store-vars writer-form reader-form)
      (get-setf-expansion place env)
    `(let ,@(mapcar (function list) vars vals)
       (let ,@(mapcar (function list) 
                      store-vars
                      `((,function ,reader-form ,@values)))
         ,writer-form))))


(macroexpand-1 '(updatef (+ (aref a (nth (incf i) l)) 2)))
-->
(LET (#:G5617 A) (#:G5618 (NTH (INCF I) L))
 (LET (#:G5619 (+ (AREF #:G5617 #:G5618) 2))
  (SYSTEM::STORE #:G5617 #:G5618 #:G5619))) ;
T

Now, you have to really like the parentheses to add gratuituous ones
like that.  Why not:

(defmacro updatef (((((function place &rest values)))) &environment env)
    ....)

while you're at it?



I'd propose a more reasonable while still as readable syntax:

(defmacro updatef (&environment env place function &rest values)
  (multiple-value-bind (vars vals store-vars writer-form reader-form)
      (get-setf-expansion place env)
    `(let ,@(mapcar (function list) vars vals)
       (let ,@(mapcar (function list) 
                      store-vars
                      `((,function ,reader-form ,@values)))
         ,writer-form))))


[39]> (macroexpand-1 '(updatef (aref a (nth (incf i) l)) + 2 3 4))
(LET (#:G5623 A) (#:G5624 (NTH (INCF I) L))
 (LET (#:G5625 (+ (AREF #:G5623 #:G5624) 2 3 4))
  (SYSTEM::STORE #:G5623 #:G5624 #:G5625))) ;
T
[40]> (macroexpand-1 '(updatef (car (aref a (nth (incf i) l))) + 2 3 4))
(LET (#:G5627 (AREF A (NTH (INCF I) L)))
 (LET (#:G5626 (+ (CAR #:G5627) 2 3 4)) 
   (SYSTEM::%RPLACA #:G5627 #:G5626))) ;
T


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

"Debugging?  Klingons do not debug! Our software does not coddle the
weak."
From: Ken Tilton
Subject: Re: a += b    a ||= b
Date: 
Message-ID: <5OMVf.3149$sU4.2109@fe12.lga>
Pascal Bourguignon wrote:
> Pascal Bourguignon <······@informatimago.com> writes:
> 
> 
>>Ken Tilton <·········@gmail.com> writes:
>>
>>
>>>Pascal Bourguignon wrote:
>>>
>>>>Ken Tilton <·········@gmail.com> writes:
>>>>
>>>>
>>>>>>>No, he reads it once and setf's it once.
>>>>>>
>>>>>>Really, Ken!
>>>>>>[8]> (defmacro updatef (args)
>>>>>> (destructuring-bind (function place &rest values) args
>>>>>>   `(setf ,place (,function ,place ,@values))))
>>>>>>UPDATEF
>>>>>>[9]> (macroexpand-1 '(updatef (+ (aref a (incf i)) 2)))
>>>>>>(SETF (AREF A (INCF I)) (+ (AREF A (INCF I)) 2)) ;
>>>>>>T
>>>>>>
>>>>>
>>>>>What's your point? (Checkmate in two.)
>>>>
>>>>The point is that when you refer a place, the side effects should be
>>>>evaluated only once.
>>>>(setf       (aref a (incf i)) 1)  ; increments i once
>>>>(updatef (+ (aref a (incf i)) 1)) ; increments i twice
>>>>Of course, you can specify updatef otherwise, but then you should
>>>>call
>>>>it:  updatef/double-side-effects
>>>>
>>>
>>>Fine. So how do you fix updatef? With a gensym? (Mate in one. <g>)
>>
>>With GET-SETF-EXPANSION.

Oh, OK, I was having trouble figuring out what define-setf-expander 
would do for you. :)

> 
> 
> Ok, no time to wait for your mate.

Looks like you found it already. The form /was/ being subjected to dual 
evaluation, but once as a reader and once as a setf place. Thems are 
different, as you realized when I asked about using a gensym.

The rest is great, btw. I thought you were going to suggest a code-walker.

:)

ken

> It's even easy:
> 
> (defmacro updatef ((function place &rest values) &environment env)
>   (multiple-value-bind (vars vals store-vars writer-form reader-form)
>       (get-setf-expansion place env)
>     `(let ,@(mapcar (function list) vars vals)
>        (let ,@(mapcar (function list) 
>                       store-vars
>                       `((,function ,reader-form ,@values)))
>          ,writer-form))))
> 
> 
> (macroexpand-1 '(updatef (+ (aref a (nth (incf i) l)) 2)))
> -->
> (LET (#:G5617 A) (#:G5618 (NTH (INCF I) L))
>  (LET (#:G5619 (+ (AREF #:G5617 #:G5618) 2))
>   (SYSTEM::STORE #:G5617 #:G5618 #:G5619))) ;
> T
> 
> Now, you have to really like the parentheses to add gratuituous ones
> like that.  Why not:
> 
> (defmacro updatef (((((function place &rest values)))) &environment env)
>     ....)
> 
> while you're at it?
> 
> 
> 
> I'd propose a more reasonable while still as readable syntax:
> 
> (defmacro updatef (&environment env place function &rest values)
>   (multiple-value-bind (vars vals store-vars writer-form reader-form)
>       (get-setf-expansion place env)
>     `(let ,@(mapcar (function list) vars vals)
>        (let ,@(mapcar (function list) 
>                       store-vars
>                       `((,function ,reader-form ,@values)))
>          ,writer-form))))
> 
> 
> [39]> (macroexpand-1 '(updatef (aref a (nth (incf i) l)) + 2 3 4))
> (LET (#:G5623 A) (#:G5624 (NTH (INCF I) L))
>  (LET (#:G5625 (+ (AREF #:G5623 #:G5624) 2 3 4))
>   (SYSTEM::STORE #:G5623 #:G5624 #:G5625))) ;
> T
> [40]> (macroexpand-1 '(updatef (car (aref a (nth (incf i) l))) + 2 3 4))
> (LET (#:G5627 (AREF A (NTH (INCF I) L)))
>  (LET (#:G5626 (+ (CAR #:G5627) 2 3 4)) 
>    (SYSTEM::%RPLACA #:G5627 #:G5626))) ;
> T
> 
> 


-- 
Cells: http://common-lisp.net/project/cells/

"And I will know my song well before I start singing."  - Bob Dylan
From: Pascal Bourguignon
Subject: Re: a += b    a ||= b
Date: 
Message-ID: <87psk7hou1.fsf@thalassa.informatimago.com>
Ken Tilton <·········@gmail.com> writes:
>>>>Fine. So how do you fix updatef? With a gensym? (Mate in one. <g>)
>>>
>>>With GET-SETF-EXPANSION.
>
> Oh, OK, I was having trouble figuring out what define-setf-expander
> would do for you. :)

Well, they all fall into my category "setf-expanders" :-)

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

NOTE: The most fundamental particles in this product are held
together by a "gluing" force about which little is currently known
and whose adhesive power can therefore not be permanently
guaranteed.
From: Barry Fishman
Subject: Re: a += b    a ||= b
Date: 
Message-ID: <m3psk7bzct.fsf@barryfishman.earthlink.net>
Pascal Bourguignon <······@informatimago.com> writes:
> I'd propose a more reasonable while still as readable syntax:
>
> (defmacro updatef (&environment env place function &rest values)
>   (multiple-value-bind (vars vals store-vars writer-form reader-form)
>       (get-setf-expansion place env)
>     `(let ,@(mapcar (function list) vars vals)
>        (let ,@(mapcar (function list) 
>                       store-vars
>                       `((,function ,reader-form ,@values)))
>          ,writer-form))))
>
>
> [39]> (macroexpand-1 '(updatef (aref a (nth (incf i) l)) + 2 3 4))
> (LET (#:G5623 A) (#:G5624 (NTH (INCF I) L))
>  (LET (#:G5625 (+ (AREF #:G5623 #:G5624) 2 3 4))
>   (SYSTEM::STORE #:G5623 #:G5624 #:G5625))) ;
> T
> [40]> (macroexpand-1 '(updatef (car (aref a (nth (incf i) l))) + 2 3 4))
> (LET (#:G5627 (AREF A (NTH (INCF I) L)))
>  (LET (#:G5626 (+ (CAR #:G5627) 2 3 4)) 
>    (SYSTEM::%RPLACA #:G5627 #:G5626))) ;
> T

Sorry to be pedantic, but shouldn't that be:

(defmacro updatef (&environment env place function &rest values)
  (multiple-value-bind (vars vals store-vars writer-form reader-form)
      (get-setf-expansion place env)
    `(let ,(mapcar (function list) vars vals)
       (let ,(mapcar (function list)
                      store-vars
                      `((,function ,reader-form ,@values)))
         ,writer-form))))

-- 
Barry Fishman
From: Pascal Bourguignon
Subject: Re: a += b    a ||= b
Date: 
Message-ID: <87bqvrhkjh.fsf@thalassa.informatimago.com>
Barry Fishman <············@earthlink.net> writes:

> Pascal Bourguignon <······@informatimago.com> writes:
>> I'd propose a more reasonable while still as readable syntax:
>>
>> (defmacro updatef (&environment env place function &rest values)
>>   (multiple-value-bind (vars vals store-vars writer-form reader-form)
>>       (get-setf-expansion place env)
>>     `(let ,@(mapcar (function list) vars vals)
>>        (let ,@(mapcar (function list) 
>>                       store-vars
>>                       `((,function ,reader-form ,@values)))
>>          ,writer-form))))
>>
>>
>> [39]> (macroexpand-1 '(updatef (aref a (nth (incf i) l)) + 2 3 4))
>> (LET (#:G5623 A) (#:G5624 (NTH (INCF I) L))
>>  (LET (#:G5625 (+ (AREF #:G5623 #:G5624) 2 3 4))
>>   (SYSTEM::STORE #:G5623 #:G5624 #:G5625))) ;
>> T
>> [40]> (macroexpand-1 '(updatef (car (aref a (nth (incf i) l))) + 2 3 4))
>> (LET (#:G5627 (AREF A (NTH (INCF I) L)))
>>  (LET (#:G5626 (+ (CAR #:G5627) 2 3 4)) 
>>    (SYSTEM::%RPLACA #:G5627 #:G5626))) ;
>> T
>
> Sorry to be pedantic, but shouldn't that be:
>
> (defmacro updatef (&environment env place function &rest values)
>   (multiple-value-bind (vars vals store-vars writer-form reader-form)
>       (get-setf-expansion place env)
>     `(let ,(mapcar (function list) vars vals)
>        (let ,(mapcar (function list)
>                       store-vars
>                       `((,function ,reader-form ,@values)))
>          ,writer-form))))

Oops, perfectly.  Don't know what I was thinking with these ,@...

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

THIS IS A 100% MATTER PRODUCT: In the unlikely event that this
merchandise should contact antimatter in any form, a catastrophic
explosion will result.
From: Kaz Kylheku
Subject: Re: a += b a ||= b
Date: 
Message-ID: <1143506552.788297.230580@v46g2000cwv.googlegroups.com>
Pascal Bourguignon wrote:
> Oops, perfectly.  Don't know what I was thinking with these ,@...

I do know!

  ``There seems to be some splicy-looking kind of stuff going on here;
let's
    throw some ,@ at it and see what happens.''

:)
From: Benjamin Teuber
Subject: Re: a += b    a ||= b
Date: 
Message-ID: <e09m6b$lhq$1@kohl.informatik.uni-bremen.de>
>> (defmacro updatef (&environment env place function &rest values)
>>   (multiple-value-bind (vars vals store-vars writer-form reader-form)
>>       (get-setf-expansion place env)
>>     `(let ,(mapcar (function list) vars vals)
>>        (let ,(mapcar (function list)
>>                       store-vars
>>                       `((,function ,reader-form ,@values)))
>>          ,writer-form))))
> 
> Oops, perfectly.  Don't know what I was thinking with these ,@...
> 

I'm just experimenting with reader-macros.
Is there some code using a !-reader-mac that makes the syntactic suger

(!+ a 44)

and friends (you should be able to use an arbitary function after !) work?
From: Pascal Bourguignon
Subject: Re: a += b    a ||= b
Date: 
Message-ID: <873bh3h85n.fsf@thalassa.informatimago.com>
Benjamin Teuber <······@web.de> writes:

>>> (defmacro updatef (&environment env place function &rest values)
>>>   (multiple-value-bind (vars vals store-vars writer-form reader-form)
>>>       (get-setf-expansion place env)
>>>     `(let ,(mapcar (function list) vars vals)
>>>        (let ,(mapcar (function list)
>>>                       store-vars
>>>                       `((,function ,reader-form ,@values)))
>>>          ,writer-form))))
>> Oops, perfectly.  Don't know what I was thinking with these ,@...
>> 
>
> I'm just experimenting with reader-macros.
> Is there some code using a !-reader-mac that makes the syntactic suger
>
> (!+ a 44)
>
> and friends (you should be able to use an arbitary function after !) work?

You don't need it.  Just insert a space!

(defmacro ! (&environment env function place &rest values)
   (multiple-value-bind (vars vals store-vars writer-form reader-form)
       (get-setf-expansion place env)
     `(let ,(mapcar (function list) vars vals)
        (let ,(mapcar (function list)
                       store-vars
                       `((,function ,reader-form ,@values)))
          ,writer-form))))

(! + a 44)


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
In deep sleep hear sound,
Cat vomit hairball somewhere.
Will find in morning.
From: Benjamin Teuber
Subject: Re: a += b    a ||= b
Date: 
Message-ID: <e09mrt$lmo$1@kohl.informatik.uni-bremen.de>
Pascal Bourguignon wrote:
> You don't need it.  Just insert a space!

Haha, this is too easy =)
The question was more out of interest in manipulating the reader and 
seeing how powerful it is...
From: Pascal Bourguignon
Subject: Re: a += b    a ||= b
Date: 
Message-ID: <87y7yvfs7e.fsf@thalassa.informatimago.com>
Benjamin Teuber <······@web.de> writes:

> Pascal Bourguignon wrote:
>> You don't need it.  Just insert a space!
>
> Haha, this is too easy =)
> The question was more out of interest in manipulating the reader and
> seeing how powerful it is...


There is no difficulty.

(defmacro updatef (&environment env place function &rest values)
   (multiple-value-bind (vars vals store-vars writer-form reader-form)
       (get-setf-expansion place env)
     `(let ,(mapcar (function list) vars vals)
        (let ,(mapcar (function list)
                       store-vars
                       `((,function ,reader-form ,@values)))
          ,writer-form))))

(set-macro-character #\!
     (lambda (stream char) 
       (let ((function (read stream t nil t))
             (args     (read stream t nil t)))
         `(updatef ,(first args) ,function ,@(rest args)))))


[46]> (read-from-string "!+(a b c)")
(UPDATEF A + B C) ;
9


Now, in the time it took you to write these two posts, not even
counting the round trip time, you could have read CLHS
set-macro-character and learnt much more thant what you could learn by
reading this trivial reader macro, IMHO.

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

PUBLIC NOTICE AS REQUIRED BY LAW: Any use of this product, in any
manner whatsoever, will increase the amount of disorder in the
universe. Although no liability is implied herein, the consumer is
warned that this process will ultimately lead to the heat death of
the universe.
From: Benjamin Teuber
Subject: Re: a += b    a ||= b
Date: 
Message-ID: <e0akef$t8p$1@kohl.informatik.uni-bremen.de>
Pascal Bourguignon wrote:
> [46]> (read-from-string "!+(a b c)")
> (UPDATEF A + B C) ;
> 9

Oh, that one I did figure out on my own already. The problem I tried as 
a practice rather was trying to get EXACTLY the (!+ x 42) syntax. This 
seems difficult as the thing !+ returns will be evaluated again. I think 
I can't create anonymous macros, so this should be a function.

I tried

(set-macro-character #\!
		     #'(lambda (stream char)
			 `#'(lambda (place arg)
			      (updatef (,(read stream t nil t)
					place
					arg)))))

but something seems to be wrong with it. Anyways, it doesn't support a 
&rest argument and I don't see a way to propagate a varying number of 
args to the updatef-call (maybe that might work with eval...)
From: Alexander Schmolck
Subject: Re: a += b    a ||= b
Date: 
Message-ID: <yfsslp3do10.fsf@oc.ex.ac.uk>
Benjamin Teuber <······@web.de> writes:

> Pascal Bourguignon wrote:
> > [46]> (read-from-string "!+(a b c)")
> > (UPDATEF A + B C) ;
> > 9
> 
> Oh, that one I did figure out on my own already. The problem I tried as a
> practice rather was trying to get EXACTLY the (!+ x 42) syntax. 

(read-from-string "(!+ x 42)") => ((lambda () (updatef !+ x 42)))

'as
From: Benjamin Teuber
Subject: Re: a += b    a ||= b
Date: 
Message-ID: <e0b7vd$4mr$1@kohl.informatik.uni-bremen.de>
Ah cool, so this works:

(set-macro-character #\!
		     #'(lambda (stream char)
			 (let ((tokens
				(prog1
				    (read-delimited-list #\) stream t)
				  (unread-char #\) stream))))	
			   `(lambda () ;the missing # seems correct
				(updatef ,tokens)))))

Maybe the result is a bit inefficient, but I guess the compiler should 
fix this (if Scheme even makes this optimization part of the 
language-spec I think my acl8 should be smart enough, too..)

Though I do like the idea of abusing the reader in the way Pascal 
pointed to. How about an ebnf-reader-difinition-language that supports 
adding any crazy syntax your like? Our friend Mikalai could even use 
this to define TwinLisp and stuff...
From: Pascal Bourguignon
Subject: Re: a += b    a ||= b
Date: 
Message-ID: <87lkuvf2rw.fsf@thalassa.informatimago.com>
Benjamin Teuber <······@web.de> writes:

> Pascal Bourguignon wrote:
>> [46]> (read-from-string "!+(a b c)")
>> (UPDATEF A + B C) ;
>> 9
>
> Oh, that one I did figure out on my own already. The problem I tried
> as a practice rather was trying to get EXACTLY the (!+ x 42)
> syntax. This seems difficult as the thing !+ returns will be evaluated
> again. I think I can't create anonymous macros, so this should be a
> function.
>
> I tried
>
> (set-macro-character #\!
> 		     #'(lambda (stream char)
> 			 `#'(lambda (place arg)
> 			      (updatef (,(read stream t nil t)
> 					place
> 					arg)))))
>
> but something seems to be wrong with it. Anyways, it doesn't support a
> &rest argument and I don't see a way to propagate a varying number of
> args to the updatef-call (maybe that might work with eval...)

For this, (!+ x 42), you must note that the parentheses are read by
the parentheses reader macro, which is calling recusively read on each
of the items inside the parentheses until it finds the closing
parenthesis. The best you can do, is to read yourself these items
until you peek the closing parenthesis (you must leave it for the
caller reader macro).  And since a read macro, as the read function,
can only reurm one lisp object, you will be able to return only one
lisp object, the updatef form, which now finds itself inside 
additionnal parentheses.

To avoid this, you'd have to  rewrite the parenthesis reader macro, to
be able to special case the ! character as first item in the list.
(Then there wouldn't have any need for a ! reader macro, you could do
everything inside the ( reader macro.)

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

HEALTH WARNING: Care should be taken when lifting this product,
since its mass, and thus its weight, is dependent on its velocity
relative to the user.
From: Tobias C. Rittweiler
Subject: Re: a += b    a ||= b
Date: 
Message-ID: <87veu0j0ks.fsf@GNUlot.localnet>
"Tobias C. Rittweiler" <···@freebits.de> writes:

> "Jimka" <·····@rdrop.com> writes:
>
> > So a += b             becomes (updatef (plus a b))
> >    a ||= b || c || d  becomes (updatef (or a b c d))
>
> How about OP=, OPSETF or, for the pun, err, fun of it, OPDATEF?

And change semantics to (OPDATEF OP PLACE &REST VALUES) like

  (OP= #'+ (cadr some-list) a b c)

  or

  (OPDATEF #'+ (cadr some-list) a b c)

  -T.
From: Kalle Olavi Niemitalo
Subject: Re: a += b    a ||= b
Date: 
Message-ID: <87wtefb05x.fsf@Astalo.kon.iki.fi>
"Jimka" <·····@rdrop.com> writes:

> (defmacro updatef (args)
>   (destructuring-bind (function place &rest values) args
>     `(setf ,place (,function ,place ,@values))))

Emacs Lisp has a somewhat similar macros named callf and callf2
(by analogy with prog2), in cl-macs.el.
From: Johan Bockgård
Subject: Re: a += b    a ||= b
Date: 
Message-ID: <yoijd5g64rsb.fsf@linus003.dd.chalmers.se>
Kalle Olavi Niemitalo <···@iki.fi> writes:

> "Jimka" <·····@rdrop.com> writes:
>
>> (defmacro updatef (args)
>>   (destructuring-bind (function place &rest values) args
>>     `(setf ,place (,function ,place ,@values))))
>
> Emacs Lisp has a somewhat similar macros named callf and callf2 (by
> analogy with prog2), in cl-macs.el.

Paul Graham calls it "_f" (in On Lisp).

-- 
Johan Bockgård