Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

macro to add let-statements automatically

79 views
Skip to first unread message

Florian Dietz

unread,
Nov 11, 2012, 5:57:28 PM11/11/12
to
I am trying to write a rather complicated macro and would like to know how to do this efficiently. The problem is that each use of the macro alters the whole function it is contained in:

the macro should have this form when used: (<macro> <symbol> <value>)
It should act just like setq, but for each use of the macro in a function (that is, anywhere in the function), the function should get a let statement to make the symbol locally scoped (initialized to nil). This would make it possible to ignore writing let statements. an example:

(lambda ()
(if *a* (<macro> a 1) (<macro> a 2))
(<macro> b (* a 2))
b)

should become:

(lambda () (let ((a nil) (b nil))
(if *a* (setq a 1) (setq a 2))
(setq b (* a 2))
b))

How can I do this?

Mirko Vukovic

unread,
Nov 11, 2012, 7:54:53 PM11/11/12
to
What you need is something like this

(lambda ()
(with-implied-lets
(if *a* (setq !a 1) (setq !a 2))
(setq !b (* a 2))
b)

Notice the `with-implied-lets' and the `!' flags.

`with-implied-lets' will parse the form, collect the flagged symbols, and build a let statement for them. And then, it will create the body form, but with the flags `!' stripped.

This technique is explained in Ch. 3 of Doug Hoyte's Let over Lambda. See the defmacro/g!

Mirko

Marco Antoniotti

unread,
Nov 12, 2012, 4:04:43 AM11/12/12
to
I would go another way and reuse a word that CL has available. My macro would use BEGIN as its name and something like ':=' as assignment, in order to avoid the '!', which, I believe, either uses up a reader macro or messes up variable names.

E.g.

(begin (:= ft 42) (+ ft 42) (:= zot (list 1 2 3)) (cons ft zot))
==>
(block XXX (let ((ft 42)) (+ ft 42) (let ((zot (list 1 2 3))) (cons ft zot))))

You need the ':=' (or '<-', or whatever) to avoid capturing outer LET bindings. Of course, all sorts of source code transformation/optimization are available.

--
MA

WJ

unread,
Nov 12, 2012, 11:18:16 AM11/12/12
to
Florian Dietz wrote:

> I am trying to write a rather complicated macro and would like to know how to do this efficiently. The problem is that each use of the macro alters the whole function it is contained in:
>
> the macro should have this form when used: (<macro> <symbol> <value>)
> It should act just like setq, but for each use of the macro in a function (that is, anywhere in the function), the function should get a let statement to make the symbol locally scoped (initialized to nil). This would make it possible to ignore writing let statements. an example:
>
> (lambda ()
> (if a (<macro> a 1) (<macro> a 2))
> (<macro> b (* a 2))
> b)
>
> should become:
>
> (lambda () (let ((a nil) (b nil))
> (if a (setq a 1) (setq a 2))
> (setq b (* a 2))
> b))
>
> How can I do this?

Do you really need this? What's wrong with simply typing

(lambda ()
(let (a b))
(if a (setq a 1) (setq a 2))

Raymond Wiker

unread,
Nov 12, 2012, 2:02:43 PM11/12/12
to
Ohohohoho... a sitting duck if there ever was one.

For starters, you have one ")" too many... no doubt you should have
spent more time working with Common Lisp instead of devising solutions
to trivial problems in lesser languages. It's a bit ironic that you post
this so soon after you criticized Erik Naggum for posting an un-tested
code snippet 10 years ago (or so).

You're right about one thing, though: this is not an actual problem, and
"solving" it will only cause problems.

budden

unread,
Nov 15, 2012, 2:01:59 AM11/15/12
to
Hi Florian, List!

I use more general thing for a couple years.

(macroexpand-1
'(proga
(multiple-value-bind (a b) (values 1 2))
(let b 2)
(flet f () a)
(f))

(multiple-value-bind (a b)
(values 1 2)
(let ((b 2))
(flet ((f () a)) (f))))

You can extend proga to understand any particular macro, e.g.
(proga
(with-open-file f "name" :direction :input)
(read-line f))

Source (under permissive license) is here:
http://code.google.com/p/def-symbol-readmacro/
I still think it might be reasonable to transform
(proga
(some-macro . something)
.
body)

To
(some-macro something . body)

Where some-macro is a macro with lambda-list (something &body body)
Proga is not perfect yet, but it is usable and I find it useful.
It saved me many hours of visual parsing of parens.

budden

unread,
Nov 15, 2012, 2:10:56 AM11/15/12
to
This is not a solution for your problem, though.

For your case, I would write simply
(lambda ()
(let*
((a (if *a* 1 2))
(b (* a 2)))
b))

OR

(lambda ()
(proga
(let a (if *a* 1 2))
(let b (* a 2))
b
)
)
0 new messages