[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.lisp

define-modify-macro is cool

Jim Newton

3/30/2016 3:39:00 PM

Has anyone used define-modify-macro? it's pretty cool.
You can define setf-er macros very easily.

Rather than writing (setf (getf obj :xyz) (or (getf obj :xyz) (foo)))
You can instead just write (orf (getf obj :xyz) (foo))
I.e., I want to setf (getf obj :xyz) to the return value of (foo) UNLESS it is already set to non-nil.

Provided you've defined orf as follows:

(define-modify-macro orf (&rest args) or)

20 Answers

William James

3/30/2016 4:19:00 PM

0

Jim Newton wrote:

> I.e., I want to setf (getf obj
> :xyz) to the return value of (foo
> ) UNLESS it is already set to non-nil.

MatzLisp (Ruby):

a = 22
==>22
b = nil
==>nil
a ||= 888
==>22
b ||= 888
==>888
[a,b]
==>[22, 888]

ary = [333]
==>[333]
ary[2] ||= 9999
==>9999
ary
==>[333, nil, 9999]

--
The NCA launched a major investigation into the scandal after a damning report
by Professor Alex Jay last year revealed that as many as 1,400 children had
been raped, trafficked, and groomed by mainly Asian gangs in the South Yorkshire
town between 1997 and 2013. http://www.redicecreations.com/article.ph...

Kaz Kylheku

3/30/2016 4:23:00 PM

0

On 2016-03-30, Jim Newton <jimka.issy@gmail.com> wrote:
> Has anyone used define-modify-macro? it's pretty cool.
> You can define setf-er macros very easily.

Yes, and I provide it in the TXR Lisp dialect.

http://www.nongnu.org/txr/txr-manpage.html#...

In TXR Lisp, I have successfully experimented with an alternative
approach to "generalized places", which doesn't follow the Common Lisp
implementation strategy built around the setf expansion.
Rather, the foundation is "update expanders": which are basically
functions that write code around your code, and provide lexical
macros/functions to that code, under names that you choose.

This paragraph gives a summary for the tools available to the programmer
who wants to write a place-updating macro of some sort, or introduce a
new kind of place:

http://www.nongnu.org/txr/txr-manpage.html#...

Stefan Monnier

3/30/2016 5:50:00 PM

0

> In TXR Lisp, I have successfully experimented with an alternative
> approach to "generalized places", which doesn't follow the Common Lisp
> implementation strategy built around the setf expansion.
> Rather, the foundation is "update expanders": which are basically
> functions that write code around your code, and provide lexical
> macros/functions to that code, under names that you choose.

Interesting. I ended up with a very similar solution in Emacs's gv.el
(tho your solution additionally tries to support deleter/ssetter
operations).


Stefan

Kaz Kylheku

3/30/2016 8:01:00 PM

0

On 2016-03-30, Stefan Monnier <monnier@iro.umontreal.ca> wrote:
>> In TXR Lisp, I have successfully experimented with an alternative
>> approach to "generalized places", which doesn't follow the Common Lisp
>> implementation strategy built around the setf expansion.
>> Rather, the foundation is "update expanders": which are basically
>> functions that write code around your code, and provide lexical
>> macros/functions to that code, under names that you choose.
>
> Interesting. I ended up with a very similar solution in Emacs's gv.el
> (tho your solution additionally tries to support deleter/ssetter
> operations).

Other things worth looking at in TXR are the powerful placelet/placelet*
macros, with which you can write totally robust place-updating macros,
simply by combining the naive code that doesn't care about multiple
evaluations, with place aliases which take care of the issue.

Also, the minor, but useful concept of a place macro. In TXR you can
define a macro which is only expanded when its form is used as a
syntactic place. (The form can be subject to a regular macro also: if it
has both, then the place macro takes precedence.) This is very handy if
you want to introduce a new kind of place, and it can be defined in
terms of a code transformation to some existing place. A real, albeit
trivial example from the implementation is:

(define-place-macro first (obj) ^(car ,obj))

The experiment with deletable places has been quite successful.
Even though not every kind of place can meaningfully support deletion,
and it means somewhat differen things for different places among those
that do, it basically works:

$ txr
This is the TXR Lisp interactive listener of TXR 136.
Use the :quit command or type Ctrl-D on empty line to exit.

Delete a global variable (makunbound):

1> (defvar x 3)
x
2> (del x)
3
3> x
** unbound variable x

Delete element of sequence:

4> (defvar l (list 1 2 3 4))
l
5> (del [l 2])
3
6> l
(1 2 4)

Delete hash element:

7> (defvar h #H(() (a 1) (b 2) (c 3)))
h
8> h
#H(() (a 1) (c 3) (b 2))
9> (del [h 'b])
2
10> h
#H(() (a 1) (c 3))

One invalid use:

11> (let ((x 42)) (del x))
** x is a lexical variable, thus not deletable
** during expansion at expr-11:1 of form (#:g0109)

Note the consistency of the return value of del: it always yields the value which
occupied the place prior to deletion.

Stefan Monnier

3/30/2016 8:54:00 PM

0

> Other things worth looking at in TXR are the powerful placelet/placelet*
> macros, with which you can write totally robust place-updating macros,
> simply by combining the naive code that doesn't care about multiple
> evaluations, with place aliases which take care of the issue.

IIUC, I think this is like what I called gv-letplace.

> Also, the minor, but useful concept of a place macro.

In Elisp I gave in to the cheap solution of applying normal macros (and
even compiler macros) to places. I considered adding place-macros (and
wrote the few lines of code needed for it), but haven't found any need
for it yet.

> The experiment with deletable places has been quite successful.

I was wondering: other than `del`, what other macros make use of it?


Stefan

Kaz Kylheku

3/30/2016 10:13:00 PM

0

On 2016-03-30, Stefan Monnier <monnier@iro.umontreal.ca> wrote:
>> Other things worth looking at in TXR are the powerful placelet/placelet*
>> macros, with which you can write totally robust place-updating macros,
>> simply by combining the naive code that doesn't care about multiple
>> evaluations, with place aliases which take care of the issue.
>
> IIUC, I think this is like what I called gv-letplace.
>
>> Also, the minor, but useful concept of a place macro.
>
> In Elisp I gave in to the cheap solution of applying normal macros (and
> even compiler macros) to places. I considered adding place-macros (and
> wrote the few lines of code needed for it), but haven't found any need
> for it yet.
>
>> The experiment with deletable places has been quite successful.
>
> I was wondering: other than `del`, what other macros make use of it?

Absolutely none.

We can't update a place that is being deleted, so such an update macro
cannot be contemplated.

The only possibility is that of some macro that operates on multiple
places, such that some of them end up deleted and the suriviving ones
receive values that are based on the prior state of the world. There
isn't any such macro predefined.

Madhu

3/31/2016 2:09:00 AM

0


* Stefan Monnier <jwvio03uahe.fsf-monnier+comp.lang.lisp@gnu.org> :
Wrote on Wed, 30 Mar 2016 13:50:11 -0400:

|> In TXR Lisp, I have successfully experimented with an alternative
|> approach to "generalized places", which doesn't follow the Common
|> Lisp implementation strategy built around the setf expansion.
|> Rather, the foundation is "update expanders": which are basically
|> functions that write code around your code, and provide lexical
|> macros/functions to that code, under names that you choose.
|
| Interesting. I ended up with a very similar solution in Emacs's gv.el
| (tho your solution additionally tries to support deleter/ssetter
| operations).

The subversive introduction of gv.el into elisp is one of the reasons
for my belief in the end-times. gv.el makes emacs-lisp a fundamentally
different language from what it was without this
infrastructure-introduction (elisp is now as different from the elisp of
emacs-23) as different as txr is from common-lisp). However it
dishonestly keeps the name "EMACS LISP". Stefan has also rewritten cl.el
with various new non-backwards-compatible force-upgrade-to-new-bugs
"features" and it keeps the name "CL-", like CL-GENERICS which have
nothing to do with generics ---Madhu


Paul Rubin

3/31/2016 2:15:00 AM

0

Madhu <enometh@meer.net> writes:
> The subversive introduction of gv.el into elisp is one of the reasons
> for my belief in the end-times. gv.el makes emacs-lisp a fundamentally
> different language from what it was without this

I hadn't heard of gv.el before, but it looks like a way to do CL-like
SETF and its relatives in emacs lisp. Is that such a big deal?
Meanwhile, Guile Emacs seems to be for real and able to run calc.el.
Maybe that's also the end times.

Jim Newton

4/4/2016 7:54:00 AM

0

Interesting that ruby provides this. Most infix syntax languages I've used, does not allow it.
Many languages have assignment operators such as +=, *=, /=, |= and &= but omit ||= and &&=.
CL has a very nice solution to let programmers provide their own via define-modify-macro
with one line.

On Wednesday, March 30, 2016 at 6:21:51 PM UTC+2, WJ wrote:
> Jim Newton wrote:
>
> > I.e., I want to setf (getf obj
> > :xyz) to the return value of (foo
> > ) UNLESS it is already set to non-nil.
>
> MatzLisp (Ruby):
>
> a = 22
> ==>22
> b = nil
> ==>nil
> a ||= 888
> ==>22
> b ||= 888
> ==>888
> [a,b]
> ==>[22, 888]
>
> ary = [333]
> ==>[333]
> ary[2] ||= 9999
> ==>9999
> ary
> ==>[333, nil, 9999]
>
> --
> The NCA launched a major investigation into the scandal after a damning report
> by Professor Alex Jay last year revealed that as many as 1,400 children had
> been raped, trafficked, and groomed by mainly Asian gangs in the South Yorkshire
> town between 1997 and 2013. http://www.redicecreations.com/article.ph...

Kaz Kylheku

4/4/2016 3:30:00 PM

0

On 2016-04-04, Jim Newton <jimka.issy@gmail.com> wrote:
> Interesting that ruby provides this. Most infix syntax languages I've used, does not allow it.
> Many languages have assignment operators such as +=, *=, /=, |= and &= but omit ||= and &&=.

That's simply because the syntax comes from C, which omits it. C omits
it because && and || are not arithmetic operators, but sequencing
operators: A && B ensures that B is not evaluated if A yields false.
Moreover, A && B does not have the type of A or B. It yields an int
(bool as of C99 and in C++) result no matter what are A or B.

So A &&= B doesn't generalize well; it makes sense only when A has a
type which is compatible A && B.

In 27 years of C programming, I have written this, I think,
once or twice, and may have seen this once in someone else's
code:

int A = some_condition();

/*...*/
A = A && other_condition();

/*...*/
A = A && third_condition();

The code elided by /*...*/ somehow makes it necessary. There are
some other conditions which cause some of these assignments to
be skipped or whatever:

int A = 1;

if (foo)
A = A && some_condition();

if (bar)
A = A && other_condition();

if (xyzzy)
A = A && third_condition();

If, say, foo and bar are false, then third_condition() still potentially
evaluates, and A can be true.

In CL we could just do this:

(and (if foo (some-condition) t)
(if bar (other-condition) t)
(if xyzzy (third-condition t)))

What would slightly help here would be a logical form of if which
follows the standard truth table:

A B (lif A B)
-------------------
nil nil t
nil t t
t nil nil
t t t

We have the equivalence (lif A B) <--> (or (not a) b), but that's
slightly verbose:

(and (or (not foo) (some-condition))
(or (not bar) (other-condition))
(or (not xyzzy) (third-condition)))

This translates back to C nicely:

(!foo || some_condition()) &&
(!bar || other_condition()) &&
(!xyzzy || third_condition())

If you think you need &&= in C, you perhaps didn't think hard enough, or
you are slavishly following some coding convention which proscribes long
expressions that break across several lines.