From: ·············@gmail.com
Subject: applying a macro with two parameters
Date: 
Message-ID: <1186948493.885470.149030@19g2000hsx.googlegroups.com>
I am (still) playing with my little english-japanese dictionary based
on the CD database example of chapter 3 of Seibels Practical Common
Lisp.  The dictionary is a list of plists (:english word :japanese
word)

I have ventured a bit out, and I can sort the entries by doing

(sort *db* rank-engl-entries)
or
(sort *db* rank-jpns-entries)

with the following comparison functions

(defun rank-engl-entries (entry1 entry2)
  (string-lessp (getf entry1 :english)
		(getf entry2 :english)))

(defun rank-jpns-entries (entry1 entry2)
  (string-lessp (getf entry1 :japanese)
		(getf entry2 :japanese )))

This of course calls for a macro, and I came up with this version,
that works:
(defmacro rank-entries (language)
  `#'(lambda (entry1 entry2)
       (string-lessp (getf entry1 ,language)
		     (getf entry2 ,language))))

(sort *db* (rank-entries :english)) will work fine.

But, to test it, I would like to test the macro on two individual
entries.  My unsuccesfull attempt is:
((rank-entries :english) (nth 5 *db*) (nth 6 *db*))
and clisp gives me an error message "(rank-entries :english) is not a
function name"

I was hoping that lisp would evaluate the first parenthesis to a
function and apply it to the remaining arguments.  By the way doing
(rank-entries: english) returns
#<FUNCTION :LAMBDA (ENTRY1 ENTRY2)
  (STRING-LESSP (GETF ENTRY1 :ENGLISH) (GETF ENTRY2 :ENGLISH))>
(looks reasonable to me).

I guess I am missing a bit of syntax to tell the interpreter what I am
trying to accomplish.

Thanks,

Mirko

From: Kent M Pitman
Subject: Re: applying a macro with two parameters
Date: 
Message-ID: <uabsw1k10.fsf@nhplace.com>
·············@gmail.com writes:

> But, to test it, I would like to test the macro on two individual
> entries.  My unsuccesfull attempt is:
> ((rank-entries :english) (nth 5 *db*) (nth 6 *db*))
> and clisp gives me an error message "(rank-entries :english) is not a
> function name"

(funcall (rank-entries :english) (nth 5 *db*) (nth 6 *db*))

CL doesn't evaluate the function position of a compound form as an
expression; the function position is evaluated specially.  The
function FUNCALL is used in this case in CL to receive a normally
evaluated expression and call it on arguments.
From: ·············@gmail.com
Subject: Re: applying a macro with two parameters
Date: 
Message-ID: <1186970227.941814.107090@l70g2000hse.googlegroups.com>
On Aug 12, 6:10 pm, Kent M Pitman <······@nhplace.com> wrote:
> ·············@gmail.com writes:
> > But, to test it, I would like to test the macro on two individual
> > entries.  My unsuccesfull attempt is:
> > ((rank-entries :english) (nth 5 *db*) (nth 6 *db*))
> > and clisp gives me an error message "(rank-entries :english) is not a
> > function name"
>
> (funcall (rank-entries :english) (nth 5 *db*) (nth 6 *db*))
>
> CL doesn't evaluate the function position of a compound form as an
> expression; the function position is evaluated specially.  The
> function FUNCALL is used in this case in CL to receive a normally
> evaluated expression and call it on arguments.

Thanks Kent.  That was exactly what I was looking for,

Mirko
From: Ken Tilton
Subject: Re: applying a macro with two parameters
Date: 
Message-ID: <XLLvi.38$9N5.27@newsfe12.lga>
·············@gmail.com wrote:
> I am (still) playing with my little english-japanese dictionary based
> on the CD database example of chapter 3 of Seibels Practical Common
> Lisp.  The dictionary is a list of plists (:english word :japanese
> word)

Jesus H, another potty-pants newby. :( D-Con works great for cockroaches....

> 
> I have ventured a bit out, and I can sort the entries by doing
> 
> (sort *db* rank-engl-entries)
> or
> (sort *db* rank-jpns-entries)
> 
> with the following comparison functions
> 
> (defun rank-engl-entries (entry1 entry2)
>   (string-lessp (getf entry1 :english)
> 		(getf entry2 :english)))
> 
> (defun rank-jpns-entries (entry1 entry2)
>   (string-lessp (getf entry1 :japanese)
> 		(getf entry2 :japanese )))
> 
> This of course calls for a macro,...

Of course. You have been doing Lisp for a week, you know exactly when to 
cut in the macro meta-booster.


> and I came up with this version,

We are so frickin excited. Come up with this: how many dozen more cases 
of this do you expect? <sigh>

I need a new obscure language, Lisp is frickin /popular/ <spit><spit>. I 
blame Erik.

> that works:
> (defmacro rank-entries (language)
>   `#'(lambda (entry1 entry2)
>        (string-lessp (getf entry1 ,language)
> 		     (getf entry2 ,language))))
> 
> (sort *db* (rank-entries :english)) will work fine.

I'll alert the media.

> 
> But, to test it, I would like to test the macro on two individual
> entries.  My unsuccesfull attempt is:
> ((rank-entries :english) (nth 5 *db*) (nth 6 *db*))
> and clisp gives me an error message "(rank-entries :english) is not a
> function name"

Jeez, I wonder what that means.

> 
> I was hoping that lisp would evaluate the first parenthesis to a
> function and apply it to the remaining arguments.

We have a pool and a pond (Scheme). The pond would be good for you.

>  By the way doing
> (rank-entries: english) returns
> #<FUNCTION :LAMBDA (ENTRY1 ENTRY2)
>   (STRING-LESSP (GETF ENTRY1 :ENGLISH) (GETF ENTRY2 :ENGLISH))>
> (looks reasonable to me).
> 
> I guess I am missing a bit of syntax to tell the interpreter what I am
> trying to accomplish.

I am wondering what would happen if you left off the #', but to be 
honest I am not real strong on how things like:

     ((lambda (x) (+ 2 x)) 3)


...work.


> 
> Thanks,


Go away.

kenny

-- 
http://www.theoryyalgebra.com/

"Algebra is the metaphysics of arithmetic." - John Ray

"As long as algebra is taught in school,
there will be prayer in school." - Cokie Roberts

"Stand firm in your refusal to remain conscious during algebra."
    - Fran Lebowitz

"I'm an algebra liar. I figure two good lies make a positive."
    - Tim Allen
From: ·············@gmail.com
Subject: Re: applying a macro with two parameters
Date: 
Message-ID: <1186970050.219998.14460@d55g2000hsg.googlegroups.com>
On Aug 12, 6:23 pm, Ken Tilton <···········@optonline.net> wrote:
> ·············@gmail.com wrote:
> > I am (still) playing with my little english-japanese dictionary based
> > on the CD database example of chapter 3 of Seibels Practical Common
> > Lisp.  The dictionary is a list of plists (:english word :japanese
> > word)
>
> Jesus H, another potty-pants newby. :( D-Con works great for cockroaches....
>
>
>
>
>
> > I have ventured a bit out, and I can sort the entries by doing
>
> > (sort *db* rank-engl-entries)
> > or
> > (sort *db* rank-jpns-entries)
>
> > with the following comparison functions
>
> > (defun rank-engl-entries (entry1 entry2)
> >   (string-lessp (getf entry1 :english)
> >            (getf entry2 :english)))
>
> > (defun rank-jpns-entries (entry1 entry2)
> >   (string-lessp (getf entry1 :japanese)
> >            (getf entry2 :japanese )))
>
> > This of course calls for a macro,...
>
> Of course. You have been doing Lisp for a week, you know exactly when to
> cut in the macro meta-booster.
>
> > and I came up with this version,
>
> We are so frickin excited. Come up with this: how many dozen more cases
> of this do you expect? <sigh>
>
> I need a new obscure language, Lisp is frickin /popular/ <spit><spit>. I
> blame Erik.
>
> > that works:
> > (defmacro rank-entries (language)
> >   `#'(lambda (entry1 entry2)
> >        (string-lessp (getf entry1 ,language)
> >                 (getf entry2 ,language))))
>
> > (sort *db* (rank-entries :english)) will work fine.
>
> I'll alert the media.
>
>
>
> > But, to test it, I would like to test the macro on two individual
> > entries.  My unsuccesfull attempt is:
> > ((rank-entries :english) (nth 5 *db*) (nth 6 *db*))
> > and clisp gives me an error message "(rank-entries :english) is not a
> > function name"
>
> Jeez, I wonder what that means.
>
>
>
> > I was hoping that lisp would evaluate the first parenthesis to a
> > function and apply it to the remaining arguments.
>
> We have a pool and a pond (Scheme). The pond would be good for you.
>
> >  By the way doing
> > (rank-entries: english) returns
> > #<FUNCTION :LAMBDA (ENTRY1 ENTRY2)
> >   (STRING-LESSP (GETF ENTRY1 :ENGLISH) (GETF ENTRY2 :ENGLISH))>
> > (looks reasonable to me).
>
> > I guess I am missing a bit of syntax to tell the interpreter what I am
> > trying to accomplish.
>
> I am wondering what would happen if you left off the #', but to be
> honest I am not real strong on how things like:
>
>      ((lambda (x) (+ 2 x)) 3)
>
> ...work.
>
>
>
> > Thanks,
>
> Go away.
>
> kenny
>
> --http://www.theoryyalgebra.com/
>
> "Algebra is the metaphysics of arithmetic." - John Ray
>
> "As long as algebra is taught in school,
> there will be prayer in school." - Cokie Roberts
>
> "Stand firm in your refusal to remain conscious during algebra."
>     - Fran Lebowitz
>
> "I'm an algebra liar. I figure two good lies make a positive."
>     - Tim Allen

Thanks.  You made me smile.

Mirko
From: Pascal Bourguignon
Subject: Re: applying a macro with two parameters
Date: 
Message-ID: <87fy2ofr1h.fsf@informatimago.com>
·············@gmail.com writes:

> I am (still) playing with my little english-japanese dictionary based
> on the CD database example of chapter 3 of Seibels Practical Common
> Lisp.  The dictionary is a list of plists (:english word :japanese
> word)
>
> I have ventured a bit out, and I can sort the entries by doing
>
> (sort *db* rank-engl-entries)
> or
> (sort *db* rank-jpns-entries)
>
> with the following comparison functions
>
> (defun rank-engl-entries (entry1 entry2)
>   (string-lessp (getf entry1 :english)
> 		(getf entry2 :english)))
>
> (defun rank-jpns-entries (entry1 entry2)
>   (string-lessp (getf entry1 :japanese)
> 		(getf entry2 :japanese )))
>
> This of course calls for a macro, and I came up with this version,
> that works:

Not really.  It calls for functional factorization:

(defun rank-entries (entry1 entry2 language)
  (string-lessp (getf entry1 language) 
                (getf entry2 language)))

(defun rank-engl-entries (e1 e2) (rank-entries e1 e2 :english))
(defun rank-jpns-entries (e1 e2) (rank-entries e1 e2 :japanese))

Note that there are several standards for abreviated language names,
you should probably use one, like:

(defun rank-en-entries (e1 e2) (rank-entries e1 e2 :english))
(defun rank-jp-entries (e1 e2) (rank-entries e1 e2 :japanese))

or keep the full name.



> But, to test it, I would like to test the macro on two individual
> entries.  My unsuccesfull attempt is:
> ((rank-entries :english) (nth 5 *db*) (nth 6 *db*))
> and clisp gives me an error message "(rank-entries :english) is not a
> function name"

Indeed.  In Common Lisp, the operator is NOT evaluated.  It must be a
literal operator name, or a literal lambda expression.


> I was hoping that lisp would evaluate the first parenthesis to a
> function and apply it to the remaining arguments.  By the way doing
> (rank-entries: english) returns
> #<FUNCTION :LAMBDA (ENTRY1 ENTRY2)
>   (STRING-LESSP (GETF ENTRY1 :ENGLISH) (GETF ENTRY2 :ENGLISH))>
> (looks reasonable to me).

Well, EVALUATING (rank-entries :english) gives you this function.  But
the macro itself doesn't return a function, but a form, the lambda
expression that when evaluated gives the function.

Try: (macroexpand '(rank-entries :english))


> I guess I am missing a bit of syntax to tell the interpreter what I am
> trying to accomplish.

Macros shouldn't be called at run-time, because their arguments and
their expansion will in general need to use information that is only
available at compilation time: the lexical environment.  See the
&environment arguments to the macros.

You can, if you insist, call the macro function to expand a form at
run-time, but you have to be careful about it, and you'll have to call
EVAL which is a strong hint...


For example, assume this macro:

(defmacro m (v x)
  (assert (symbolp v))
  `(setq ,v (+ (* 2 ,v) ,x)))


(defvar *v1* 1)
(defvar *v2* 2)
(mapcar (lambda (v) (m v 1)) '(*v1* *v2*))

won't work.

You could do:

(defvar *v1* 1)
(defvar *v2* 2)
(mapc (lambda (v) (eval (macroexpand `(m ,v 1)))) '(*v1* *v2*))

and this would seem to work, but:

(let ((v1 1)
      (v2 2))
  (mapc (lambda (v) (eval (macroexpand `(m ,v 1)))) '(v1 v2))
  (print (list v1 v2)))

cannot work in Common Lisp and won't work in most implementation.


You could persist and write:

(let ((v1 1)
      (v2 2))
  (mapc (lambda (v) 
          (multiple-value-setq (v1 v2)
             (funcall (compile nil 
                `(lambda () 
                   (let ((v1 ,v1)
                         (v2 ,v2))
                       (m ,v 1)
                       (values v1 v2)))))))  '(v1 v2))
  (print (list v1 v2)))


but I hope you now realize that it would be simplier to write a function:

(defun f (v x) (+ (* 2 v) x))

(let ((v1 1)
      (v2 2))
 (setf v1 (f v1 1)
       v2 (f v2 1))
  (print (list v1 v2)))

If you want to save some copy-and-paste, you can always write a macro to do that:

(let ((v1 1)
      (v2 2))
 (macrolet ((u (v) `(setf ,v (f ,v 1))))
   (u v1) 
   (u v2))
 (print (list v1 v2)))

or even:

(let ((v1 1)
      (v2 2))
 (macrolet ((u (&rest vs) `(progn ,@(mapcar (lambda (v) `(setf ,v (f ,v 1))) vs))))
   (u v1 v2))
 (print (list v1 v2)))

But the macro is not here to factorize your functions, but to
factorize your typing...  Some will frown on this kind of macros.

-- 
__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: ·············@gmail.com
Subject: Re: applying a macro with two parameters
Date: 
Message-ID: <1186972713.380306.314860@g4g2000hsf.googlegroups.com>
On Aug 12, 4:15 pm, Pascal Bourguignon <····@informatimago.com> wrote:
> ·············@gmail.com writes:
> > I am (still) playing with my little english-japanese dictionary based
> > on the CD database example of chapter 3 of Seibels Practical Common
> > Lisp.  The dictionary is a list of plists (:english word :japanese
> > word)
>
> > I have ventured a bit out, and I can sort the entries by doing
>
> > (sort *db* rank-engl-entries)
> > or
> > (sort *db* rank-jpns-entries)
>
> > with the following comparison functions
>
> > (defun rank-engl-entries (entry1 entry2)
> >   (string-lessp (getf entry1 :english)
> >            (getf entry2 :english)))
>
> > (defun rank-jpns-entries (entry1 entry2)
> >   (string-lessp (getf entry1 :japanese)
> >            (getf entry2 :japanese )))
>
> > This of course calls for a macro, and I came up with this version,
> > that works:
>
> Not really.  It calls for functional factorization:
>
> (defun rank-entries (entry1 entry2 language)
>   (string-lessp (getf entry1 language)
>                 (getf entry2 language)))
>
> (defun rank-engl-entries (e1 e2) (rank-entries e1 e2 :english))
> (defun rank-jpns-entries (e1 e2) (rank-entries e1 e2 :japanese))

You are right, this is so much simpler.
>
> Note that there are several standards for abreviated language names,
> you should probably use one, like:
>
> (defun rank-en-entries (e1 e2) (rank-entries e1 e2 :english))
> (defun rank-jp-entries (e1 e2) (rank-entries e1 e2 :japanese))
>
> or keep the full name.
Noted, thanks

Mirko
>
> > But, to test it, I would like to test the macro on two individual
> > entries.  My unsuccesfull attempt is:
> > ((rank-entries :english) (nth 5 *db*) (nth 6 *db*))
> > and clisp gives me an error message "(rank-entries :english) is not a
> > function name"
>
> Indeed.  In Common Lisp, the operator is NOT evaluated.  It must be a
> literal operator name, or a literal lambda expression.
>
> > I was hoping that lisp would evaluate the first parenthesis to a
> > function and apply it to the remaining arguments.  By the way doing
> > (rank-entries: english) returns
> > #<FUNCTION :LAMBDA (ENTRY1 ENTRY2)
> >   (STRING-LESSP (GETF ENTRY1 :ENGLISH) (GETF ENTRY2 :ENGLISH))>
> > (looks reasonable to me).
>
> Well, EVALUATING (rank-entries :english) gives you this function.  But
> the macro itself doesn't return a function, but a form, the lambda
> expression that when evaluated gives the function.
>
> Try: (macroexpand '(rank-entries :english))
>
> > I guess I am missing a bit of syntax to tell the interpreter what I am
> > trying to accomplish.
>
> Macros shouldn't be called at run-time, because their arguments and
> their expansion will in general need to use information that is only
> available at compilation time: the lexical environment.  See the
> &environment arguments to the macros.

I can see why Ken gets exasperated by newbie questions :-)

>
> You can, if you insist, call the macro function to expand a form at
> run-time, but you have to be careful about it, and you'll have to call
> EVAL which is a strong hint...
>
> For example, assume this macro:
>
> (defmacro m (v x)
>   (assert (symbolp v))
>   `(setq ,v (+ (* 2 ,v) ,x)))
>
> (defvar *v1* 1)
> (defvar *v2* 2)
> (mapcar (lambda (v) (m v 1)) '(*v1* *v2*))
>
> won't work.
>
> You could do:
>
> (defvar *v1* 1)
> (defvar *v2* 2)
> (mapc (lambda (v) (eval (macroexpand `(m ,v 1)))) '(*v1* *v2*))
>
> and this would seem to work, but:
>
> (let ((v1 1)
>       (v2 2))
>   (mapc (lambda (v) (eval (macroexpand `(m ,v 1)))) '(v1 v2))
>   (print (list v1 v2)))
>
> cannot work in Common Lisp and won't work in most implementation.
>
> You could persist and write:
>
> (let ((v1 1)
>       (v2 2))
>   (mapc (lambda (v)
>           (multiple-value-setq (v1 v2)
>              (funcall (compile nil
>                 `(lambda ()
>                    (let ((v1 ,v1)
>                          (v2 ,v2))
>                        (m ,v 1)
>                        (values v1 v2)))))))  '(v1 v2))
>   (print (list v1 v2)))
>
> but I hope you now realize that it would be simplier to write a function:
>
> (defun f (v x) (+ (* 2 v) x))
>
> (let ((v1 1)
>       (v2 2))
>  (setf v1 (f v1 1)
>        v2 (f v2 1))
>   (print (list v1 v2)))
>
> If you want to save some copy-and-paste, you can always write a macro to do that:
>
> (let ((v1 1)
>       (v2 2))
>  (macrolet ((u (v) `(setf ,v (f ,v 1))))
>    (u v1)
>    (u v2))
>  (print (list v1 v2)))
>
> or even:
>
> (let ((v1 1)
>       (v2 2))
>  (macrolet ((u (&rest vs) `(progn ,@(mapcar (lambda (v) `(setf ,v (f ,v 1))) vs))))
>    (u v1 v2))
>  (print (list v1 v2)))

hmm.  Scheme is sounding better and better to these newbie eyes :-)
>
> But the macro is not here to factorize your functions, but to
> factorize your typing...
ok.


Thanks,

Mirko
From: Ken Tilton
Subject: Re: applying a macro with two parameters
Date: 
Message-ID: <7HZvi.3039$Qn6.2704@newsfe12.lga>
·············@gmail.com wrote:
> hmm.  Scheme is sounding better and better to these newbie eyes :-)

Need help moving?

Meanwhile, congratulations on your consistency in judging me after a 
grand total of one article, and in getting that wrong, too. I only 
object to newby questions that come in the form of an answer ("of 
/course/ this calls for a macro..."). I figure anyone ballsy enough to 
grandstand like that in a group known for its savagery can take a little 
abuse. If not, I recommend #lisp IRC, they are much kinder/gentler to 
outsiders.

hth,kxo
From: Frank Buss
Subject: Re: applying a macro with two parameters
Date: 
Message-ID: <1fwnbl57kgjp5$.vvvu9qrdmsop.dlg@40tude.net>
Ken Tilton wrote:

> I figure anyone ballsy enough to 
> grandstand like that in a group known for its savagery can take a little 
> abuse. If not, I recommend #lisp IRC, they are much kinder/gentler to 
> outsiders.

*LOL*

-- 
Frank Buss, ··@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
From: Barry Margolin
Subject: Re: applying a macro with two parameters
Date: 
Message-ID: <barmar-075C11.20300312082007@comcast.dca.giganews.com>
In article <··············@informatimago.com>,
 Pascal Bourguignon <···@informatimago.com> wrote:

> ·············@gmail.com writes:
> 
> > I am (still) playing with my little english-japanese dictionary based
> > on the CD database example of chapter 3 of Seibels Practical Common
> > Lisp.  The dictionary is a list of plists (:english word :japanese
> > word)
> >
> > I have ventured a bit out, and I can sort the entries by doing
> >
> > (sort *db* rank-engl-entries)
> > or
> > (sort *db* rank-jpns-entries)
> >
> > with the following comparison functions
> >
> > (defun rank-engl-entries (entry1 entry2)
> >   (string-lessp (getf entry1 :english)
> > 		(getf entry2 :english)))
> >
> > (defun rank-jpns-entries (entry1 entry2)
> >   (string-lessp (getf entry1 :japanese)
> > 		(getf entry2 :japanese )))
> >
> > This of course calls for a macro, and I came up with this version,
> > that works:
> 
> Not really.  It calls for functional factorization:
> 
> (defun rank-entries (entry1 entry2 language)
>   (string-lessp (getf entry1 language) 
>                 (getf entry2 language)))

Or a macro for defining the functions:

(define-rank-fun (name language)
  `(defun ,name (entry1 entry2)
      (string-lessp (getf entry1 ',language) (getf entry2 ',language))))

(define-rank-fun rank-engl-entries :english)
(define-rank-fun rank-jpns-entries :japanese)

But the disadvantage of this is that if you change the macro you have to 
recompile the users.  The functional version doesn't have this problem.

-- 
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
*** PLEASE don't copy me on replies, I'll read them in the group ***