[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.lisp

macro for let and let*

Taoufik Dachraoui

5/20/2015 8:18:00 AM

Hi

I want to share a macro for the parallel let that I wrote for fun,
I used the pattern matching macro that I wrote a long time ago and
that I am using for all my lisp developments:

;;; parallel let
; (let ((a va) (b vb) (c vc)) e)
; => ((fn a ((fn b ((fn c e) vc)) vb)) va)
; => ((fn xc
; ((fn xb
; ((fn a ((fn b ((fn c e) xc)) xb)) va)
; ) vb)
; ) vc)

(defmacro let (&rest e)
(match `(let . ,e)
((let (:and ?args (:match (:or nil ((:or (:type symbol) ((:type symbol) _)) . :self))))
(:lone (declare . _)) . ?s)
(loop
for i in args
for j = (if (atom i) i (car i))
for xj = (gensym)
for k = (if (atom i) nil (cadr i))
for x = `(progn . ,s)
then `(funcall (lambda (,j) ,x) ,xj)
collect xj into rj
collect k into rk
finally (return
(loop
for xj in rj
for k in rk
for xr = (if (atom (car args))
`(funcall (lambda (,(car args)) ,x) nil)
`(funcall (lambda (,(caar args)) ,x) ,(cadar args)))
then `(funcall (lambda (,xj) ,xr) ,k)
finally (return xr)))))
(_ (error "invalid let expression"))))


-Taoufik
11 Answers

Taoufik Dachraoui

5/20/2015 8:22:00 AM

0

On Wednesday, May 20, 2015 at 10:18:03 AM UTC+2, Taoufik Dachraoui wrote:
> Hi
>
> I want to share a macro for the parallel let that I wrote for fun,
> I used the pattern matching macro that I wrote a long time ago and
> that I am using for all my lisp developments:
>
> ;;; parallel let
> ; (let ((a va) (b vb) (c vc)) e)
> ; => ((fn a ((fn b ((fn c e) vc)) vb)) va)
> ; => ((fn xc
> ; ((fn xb
> ; ((fn a ((fn b ((fn c e) xc)) xb)) va)
> ; ) vb)
> ; ) vc)
>
> (defmacro let (&rest e)
> (match `(let . ,e)
> ((let (:and ?args (:match (:or nil ((:or (:type symbol) ((:type symbol) _)) . :self))))
> (:lone (declare . _)) . ?s)
> (loop
> for i in args
> for j = (if (atom i) i (car i))
> for xj = (gensym)
> for k = (if (atom i) nil (cadr i))
> for x = `(progn . ,s)
> then `(funcall (lambda (,j) ,x) ,xj)
> collect xj into rj
> collect k into rk
> finally (return
> (loop
> for xj in rj
> for k in rk
> for xr = (if (atom (car args))
> `(funcall (lambda (,(car args)) ,x) nil)
> `(funcall (lambda (,(caar args)) ,x) ,(cadar args)))
> then `(funcall (lambda (,xj) ,xr) ,k)
> finally (return xr)))))
> (_ (error "invalid let expression"))))
>
>
> -Taoufik

I forgot to pur the macro for let*:

(defmacro let* (&rest e)
(match `(let* . ,e)
((let* (:and ?args (:match (:or nil ((:or (:type symbol) ((:type symbol) _)) . :self)))) (:lone (declare . _)) . ?s)
(let ((r (if (null s) nil `(begin . ,s))))
(if (null rest)
`(funcall (lambda (,x) ,r) ,e0)
`(funcall (lambda (,x) (let* ,rest ,r)) ,e0))))
(_ (error "invalid let* expression"))))

-Taoufik

Barry Margolin

5/20/2015 2:32:00 PM

0

In article <f9369ee4-8091-4611-ac75-4b37c538ebb2@googlegroups.com>,
Taoufik Dachraoui <dachraoui.taoufik@gmail.com> wrote:

> Hi
>
> I want to share a macro for the parallel let that I wrote for fun,
> I used the pattern matching macro that I wrote a long time ago and
> that I am using for all my lisp developments:
>
> ;;; parallel let
> ; (let ((a va) (b vb) (c vc)) e)
> ; => ((fn a ((fn b ((fn c e) vc)) vb)) va)
> ; => ((fn xc
> ; ((fn xb
> ; ((fn a ((fn b ((fn c e) xc)) xb)) va)
> ; ) vb)
> ; ) vc)
>
> (defmacro let (&rest e)
> (match `(let . ,e)
> ((let (:and ?args (:match (:or nil ((:or (:type symbol) ((:type symbol)
> _)) . :self))))
> (:lone (declare . _)) . ?s)
> (loop
> for i in args
> for j = (if (atom i) i (car i))
> for xj = (gensym)
> for k = (if (atom i) nil (cadr i))
> for x = `(progn . ,s)
> then `(funcall (lambda (,j) ,x) ,xj)
> collect xj into rj
> collect k into rk
> finally (return
> (loop
> for xj in rj
> for k in rk
> for xr = (if (atom (car args))
> `(funcall (lambda (,(car args)) ,x) nil)
> `(funcall (lambda (,(caar args)) ,x) ,(cadar args)))
> then `(funcall (lambda (,xj) ,xr) ,k)
> finally (return xr)))))
> (_ (error "invalid let expression"))))
>
>
> -Taoufik

You don't need to use FUNCALL to call a lambda expression, it can be put
directly in the function position:

((lambda (x) (+ 1 x)) 3) => 4

Hopefully most implementations will optimize

(funcall (lambda (x) ...) arg)

to this.

--
Barry Margolin, barmar@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***

Stefan Monnier

5/20/2015 3:20:00 PM

0

> ((lambda (x) (+ 1 x)) 3) => 4
> Hopefully most implementations will optimize
> (funcall (lambda (x) ...) arg)

Or rather: hopefully most/all implementations will generate the same
code for both cases.


Stefan

Kaz Kylheku

5/20/2015 4:16:00 PM

0

On 2015-05-20, Taoufik Dachraoui <dachraoui.taoufik@gmail.com> wrote:
> Hi
>
> I want to share a macro for the parallel let that I wrote for fun,
> I used the pattern matching macro that I wrote a long time ago and
> that I am using for all my lisp developments:

You're using lambda as the target language, but neglecting to account
for the fact that lambda lists have syntax involving lambda list keywords:
&optional, &key, &rest, &aux.

These symbols may be used as names in let and let* binding and so can be
used to produce breaking test cases, I suspect.

Solving this problem completely and transparently is harder than
you might think.

Pascal Costanza

5/21/2015 6:45:00 AM

0

On 20/05/2015 17:20, Stefan Monnier wrote:
>> ((lambda (x) (+ 1 x)) 3) => 4
>> Hopefully most implementations will optimize
>> (funcall (lambda (x) ...) arg)
>
> Or rather: hopefully most/all implementations will generate the same
> code for both cases.
>

That's what he said. ;)

Pascal

--
My website: http:/...
Common Lisp Document Repository: http://cdr.eu...
Closer to MOP & ContextL: http://common-lisp.net/proje...
The views expressed are my own, and not those of my employer.

Barry Margolin

5/21/2015 3:04:00 PM

0

In article <jwvmw0zgtu3.fsf-monnier+comp.lang.lisp@gnu.org>,
Stefan Monnier <monnier@iro.umontreal.ca> wrote:

> > ((lambda (x) (+ 1 x)) 3) => 4
> > Hopefully most implementations will optimize
> > (funcall (lambda (x) ...) arg)
>
> Or rather: hopefully most/all implementations will generate the same
> code for both cases.

Isn't that what "optimize X to Y" means?

I suppose there could conceivably be an implementation where the version
with funcall generates better code, so it might not be an
"optimization". But in that case, "hopefully" would also be wrong.

--
Barry Margolin, barmar@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***

Stefan Monnier

5/21/2015 3:23:00 PM

0

> I suppose there could conceivably be an implementation where the version
> with funcall generates better code,

That's kind of my point. There's no reason to think that one is
fundamentally more efficient or more fundamental than the other.


Stefan "who can't guarantee that the Elisp compiler does indeed
always generate the same code for both forms"

Barry Margolin

5/21/2015 7:25:00 PM

0

In article <jwvwq02gdoi.fsf-monnier+comp.lang.lisp@gnu.org>,
Stefan Monnier <monnier@iro.umontreal.ca> wrote:

> > I suppose there could conceivably be an implementation where the version
> > with funcall generates better code,
>
> That's kind of my point. There's no reason to think that one is
> fundamentally more efficient or more fundamental than the other.

Well, if the compiler doesn't do any optimization, the one with funcall
has to call the FUNCALL function, which then has to call the function in
the lambda expression.

While anything is possible, it seems unlikely that an expression with
one less function call in the source code will do more work. Either the
compiler detects that it's redundant and removes it or it doesn't.

It might be more obvious if the comparison were between:

(foo 'bar)

and

(funcall 'foo 'bar)

It would take a pretty perverse implementation for the second to be
optimized better than the first. Either they're the same or the first
will be better.

--
Barry Margolin, barmar@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***

Pascal J. Bourguignon

5/21/2015 7:52:00 PM

0

Barry Margolin <barmar@alum.mit.edu> writes:

> In article <jwvwq02gdoi.fsf-monnier+comp.lang.lisp@gnu.org>,
> Stefan Monnier <monnier@iro.umontreal.ca> wrote:
>
>> > I suppose there could conceivably be an implementation where the version
>> > with funcall generates better code,
>>
>> That's kind of my point. There's no reason to think that one is
>> fundamentally more efficient or more fundamental than the other.
>
> Well, if the compiler doesn't do any optimization, the one with funcall
> has to call the FUNCALL function, which then has to call the function in
> the lambda expression.

No, not "has", "may" call the funcall function.
Any CL operator may be open-coded by the implementation.

Of course, the question is again, what you call "compiler
optimization".



> It might be more obvious if the comparison were between:
>
> (foo 'bar)
>
> and
>
> (funcall 'foo 'bar)

Yes. But if you were to compare (foo 'bar)
vs. (funcall (function foo) 'bar)
then in a given implementation that opencodes funcall, you might see no
difference.


> It would take a pretty perverse implementation for the second to be
> optimized better than the first. Either they're the same or the first
> will be better.

Yes.

--
__Pascal Bourguignon__ http://www.informat...
â??The factory of the future will have only two employees, a man and a
dog. The man will be there to feed the dog. The dog will be there to
keep the man from touching the equipment.� -- Carl Bass CEO Autodesk

Kaz Kylheku

5/21/2015 8:01:00 PM

0

On 2015-05-21, Barry Margolin <barmar@alum.mit.edu> wrote:
> In article <jwvwq02gdoi.fsf-monnier+comp.lang.lisp@gnu.org>,
> Stefan Monnier <monnier@iro.umontreal.ca> wrote:
>
>> > I suppose there could conceivably be an implementation where the version
>> > with funcall generates better code,
>>
>> That's kind of my point. There's no reason to think that one is
>> fundamentally more efficient or more fundamental than the other.
>
> Well, if the compiler doesn't do any optimization, the one with funcall
> has to call the FUNCALL function, which then has to call the function in
> the lambda expression.
>
> While anything is possible, it seems unlikely that an expression with
> one less function call in the source code will do more work. Either the
> compiler detects that it's redundant and removes it or it doesn't.

The pattern (funcall (function (lambda ...)) ...) occurs frequently
in macro-expanded code.

The pattern ((lambda ...) ...) is rare, and occurs primarily in goofy
or instructional code.

A Lisp compiler that neglects optimizations around funcall is more
impaired than one that overlooks ((lambda ...) ...) forms.