[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.lisp

How to search a macro argument

Helmut Jarausch

4/13/2015 7:59:00 AM

Hi,

I have a macro which takes an expression which may contain some predefined
variable names. Now I want to check if an expression contains a given name.

For example

(defmacro Show (This)
(format t "got ~A~%" (search "vx" This)))

But calling it like

(Show (1+ vx))

outputs got NIL.

Do I have to "convert" the macro argument This to a string and how can this
be done?

Many thanks for a hint,
Helmut
18 Answers

William James

4/13/2015 9:25:00 AM

0

jarausch@skynet.be wrote:

> I have a macro which takes an expression which may contain some predefined
> variable names. Now I want to check if an expression contains a given name.
>
> For example
>
> (defmacro Show (This)
> (format t "got ~A~%" (search "vx" This)))
>
> But calling it like
>
> (Show (1+ vx))
>
> outputs got NIL.
>
> Do I have to "convert" the macro argument This to a string and how can this
> be done?

A blind quadraplegic should not try to be a brain-surgeon.

Gauche Scheme:

(define-macro (try stuff)
(print (member 'vx stuff)))

(try (1+ vx))

===>
(vx)

Pascal J. Bourguignon

4/13/2015 11:10:00 AM

0

jarausch@skynet.be writes:

> Hi,
>
> I have a macro which takes an expression which may contain some predefined
> variable names. Now I want to check if an expression contains a given name.
>
> For example
>
> (defmacro Show (This)
> (format t "got ~A~%" (search "vx" This)))
>
> But calling it like
>
> (Show (1+ vx))
>
> outputs got NIL.
>
> Do I have to "convert" the macro argument This to a string and how can this
> be done?

No. You have to write what you MEAN!


cl-user> (defmacro Show (This)
(format t "got ~A~%" (search "vx" This)))
show
cl-user> (macroexpand '(show (1+ "vx")))
got nil
nil
t
cl-user> (macroexpand '(show (1+ #\v #\x)))
got 1
nil
t
cl-user> (macroexpand '(show "avxibus"))
got 1
nil
t
cl-user>


--
__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

Helmut Jarausch

4/13/2015 12:09:00 PM

0

On Monday, 13 April 2015 13:18:19 UTC+2, informatimago wrote:
> jarausch@skynet.be writes:
>
> > Hi,
> >
> > I have a macro which takes an expression which may contain some predefined
> > variable names. Now I want to check if an expression contains a given name.
> >
> > For example
> >
> > (defmacro Show (This)
> > (format t "got ~A~%" (search "vx" This)))
> >
> > But calling it like
> >
> > (Show (1+ vx))
> >
> > outputs got NIL.
> >
> > Do I have to "convert" the macro argument This to a string and how can this
> > be done?
>
> No. You have to write what you MEAN!
>
>
> cl-user> (defmacro Show (This)
> (format t "got ~A~%" (search "vx" This)))
> show
> cl-user> (macroexpand '(show (1+ "vx")))
> got nil
> nil
> t
> cl-user> (macroexpand '(show (1+ #\v #\x)))
> got 1
> nil
> t
> cl-user> (macroexpand '(show "avxibus"))
> got 1
> nil
> t

Thanks Pascal,

my situation is more complicate. Here is a cut down example

(defun myfct (arg)
(+1 arg))

(defmacro GenFct (This)
(let ((to-let
(if (search "vx" This) `(vx (myfct op)) ;;; here 'search' fails
nil)))
`(defun foo (op)
(let ((,to-let))
,This)) ;;; <<< I need This here, which must not be a string
))

The macro call

(GenFct (print vx))

should generate

(defun foo (op)
(let ((vx (myfct op)))
(print vx)))

Pascal J. Bourguignon

4/13/2015 12:50:00 PM

0

jarausch@skynet.be writes:

> On Monday, 13 April 2015 13:18:19 UTC+2, informatimago wrote:
>> jarausch@skynet.be writes:
>>
>> > Hi,
>> >
>> > I have a macro which takes an expression which may contain some predefined
>> > variable names. Now I want to check if an expression contains a given name.
>> >
>> > For example
>> >
>> > (defmacro Show (This)
>> > (format t "got ~A~%" (search "vx" This)))
>> >
>> > But calling it like
>> >
>> > (Show (1+ vx))
>> >
>> > outputs got NIL.
>> >
>> > Do I have to "convert" the macro argument This to a string and how can this
>> > be done?
>>
>> No. You have to write what you MEAN!
>>
>>
>> cl-user> (defmacro Show (This)
>> (format t "got ~A~%" (search "vx" This)))
>> show
>> cl-user> (macroexpand '(show (1+ "vx")))
>> got nil
>> nil
>> t
>> cl-user> (macroexpand '(show (1+ #\v #\x)))
>> got 1
>> nil
>> t
>> cl-user> (macroexpand '(show "avxibus"))
>> got 1
>> nil
>> t
>
> Thanks Pascal,
>
> my situation is more complicate. Here is a cut down example
>
> (defun myfct (arg)
> (+1 arg))
>
> (defmacro GenFct (This)
> (let ((to-let
> (if (search "vx" This) `(vx (myfct op)) ;;; here 'search' fails
> nil)))
> `(defun foo (op)
> (let ((,to-let))
> ,This)) ;;; <<< I need This here, which must not be a string
> ))
>
> The macro call
>
> (GenFct (print vx))
>
> should generate
>
> (defun foo (op)
> (let ((vx (myfct op)))
> (print vx)))

It cannot you have too many parentheses around ,to-let


If you could say in English what you really want, you would be able to
find the CL functions allowing you to implement it.


You've written code so that

(macroexpand-1 '(genfct (concatenate 'list vi #\v #\x en)))
--> (defun foo (op)
(let (((vx (myfct op))))
(concatenate 'list vi #\v #\x en)))

so I'd say that it works perfectly well, both in search "vx" in the
expression, and in generating a bad LET form.



--
__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

Pascal J. Bourguignon

4/13/2015 1:15:00 PM

0

jarausch@skynet.be writes:


> meanwhile I've found out that FORMAT can do the conversion.

Stop being an idiot!


> Here is what I was looking for
>
> (defun myfct (arg)
> (+1 arg))
>
> (defmacro GenFct (This)
> (let ((to-let
> (if (search "VX" (format nil "~a" This)) `(vx (myfct op))
> nil)))
> `(defun foo (op)
> (let (,to-let)
> ,This))
> ))
>
> (macroexpand-1 '(GenFct (1+ vx)))
>
> generates
>
> (DEFUN FOO (OP)
> (LET ((VX (MYFCT OP)))
> (1+ VX)))
>
> Unfortunately, in case the expression does not contain vx
> it generates the invalid LET form

What does that mean? What is vx? Do:

(+ 1 vx)

(vx 42)

(print "hello vivxen!")

(if (= a h)
(progn
(do-something (concatenate 'string viv #\v #\x en))
'ha)
(+ 42 (vx 33)))


"contain" vx???



> (LET (())
>
> Since I have several such variables I have to do more work to generate
> of leave out the LET form. It would be nicer if I could generate a
> No-Op LET form, but I don't know how.

You don't know how to generate () when there are no variable, and how to
generate ((a x) (b y)) when there are two variables???


--
__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

Helmut Jarausch

4/13/2015 1:16:00 PM

0

On Monday, 13 April 2015 14:58:10 UTC+2, informatimago wrote:
> jarausch@skynet.be writes:
>
> > On Monday, 13 April 2015 13:18:19 UTC+2, informatimago wrote:
> >> jarausch@skynet.be writes:
> >>
> >> > Hi,
> >> >
> >> > I have a macro which takes an expression which may contain some predefined
> >> > variable names. Now I want to check if an expression contains a given name.
> >> >
> >> > For example
> >> >
> >> > (defmacro Show (This)
> >> > (format t "got ~A~%" (search "vx" This)))
> >> >
> >> > But calling it like
> >> >
> >> > (Show (1+ vx))
> >> >
> >> > outputs got NIL.
> >> >
> >> > Do I have to "convert" the macro argument This to a string and how can this
> >> > be done?
> >>
> >> No. You have to write what you MEAN!
> >>
> >>
> >> cl-user> (defmacro Show (This)
> >> (format t "got ~A~%" (search "vx" This)))
> >> show
> >> cl-user> (macroexpand '(show (1+ "vx")))
> >> got nil
> >> nil
> >> t
> >> cl-user> (macroexpand '(show (1+ #\v #\x)))
> >> got 1
> >> nil
> >> t
> >> cl-user> (macroexpand '(show "avxibus"))
> >> got 1
> >> nil
> >> t
> >
> > Thanks Pascal,
> >
> > my situation is more complicate. Here is a cut down example
> >
> > (defun myfct (arg)
> > (+1 arg))
> >
> > (defmacro GenFct (This)
> > (let ((to-let
> > (if (search "vx" This) `(vx (myfct op)) ;;; here 'search' fails
> > nil)))
> > `(defun foo (op)
> > (let ((,to-let))
> > ,This)) ;;; <<< I need This here, which must not be a string
> > ))
> >
> > The macro call
> >
> > (GenFct (print vx))
> >
> > should generate
> >
> > (defun foo (op)
> > (let ((vx (myfct op)))
> > (print vx)))
>
> It cannot you have too many parentheses around ,to-let
>
>
> If you could say in English what you really want, you would be able to
> find the CL functions allowing you to implement it.
>
>
> You've written code so that
>
> (macroexpand-1 '(genfct (concatenate 'list vi #\v #\x en)))
> --> (defun foo (op)
> (let (((vx (myfct op))))
> (concatenate 'list vi #\v #\x en)))
>
> so I'd say that it works perfectly well, both in search "vx" in the
> expression, and in generating a bad LET form.
>

Thanks Pascal,

meanwhile I've found out that FORMAT can do the conversion.
Here is what I was looking for

(defun myfct (arg)
(+1 arg))

(defmacro GenFct (This)
(let ((to-let
(if (search "VX" (format nil "~a" This)) `(vx (myfct op))
nil)))
`(defun foo (op)
(let (,to-let)
,This))
))

(macroexpand-1 '(GenFct (1+ vx)))

generates

(DEFUN FOO (OP)
(LET ((VX (MYFCT OP)))
(1+ VX)))

Unfortunately, in case the expression does not contain vx
it generates the invalid LET form

(LET (())

Since I have several such variables I have to do more work to generate of leave out the LET form. It would be nicer if I could generate a No-Op LET form, but I don't know how.

Helmut

Pascal J. Bourguignon

4/13/2015 1:23:00 PM

0

jarausch@skynet.be writes:

> (defun myfct (arg)
> (+1 arg))
>
> (defmacro GenFct (This)

Also, you should choose better names for your operators and your
parameters. MYFCT, GENFCT, ARG and THIS are meaningless.

--
__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

Helmut Jarausch

4/13/2015 1:54:00 PM

0

On Monday, 13 April 2015 15:23:05 UTC+2, informatimago wrote:
> jarausch@skynet.be writes:
>
>
> > meanwhile I've found out that FORMAT can do the conversion.
>
> Stop being an idiot!

Thank you for the complements.

>
>
> > Here is what I was looking for
> >
> > (defun myfct (arg)
> > (+1 arg))
> >
> > (defmacro GenFct (This)
> > (let ((to-let
> > (if (search "VX" (format nil "~a" This)) `(vx (myfct op))
> > nil)))
> > `(defun foo (op)
> > (let (,to-let)
> > ,This))
> > ))
> >
> > (macroexpand-1 '(GenFct (1+ vx)))
> >
> > generates
> >
> > (DEFUN FOO (OP)
> > (LET ((VX (MYFCT OP)))
> > (1+ VX)))
> >
> > Unfortunately, in case the expression does not contain vx
> > it generates the invalid LET form
>
> What does that mean? What is vx? Do:
>
> (+ 1 vx)
>
> (vx 42)
>
> (print "hello vivxen!")
>
> (if (= a h)
> (progn
> (do-something (concatenate 'string viv #\v #\x en))
> 'ha)
> (+ 42 (vx 33)))
>
>
> "contain" vx???

In my case I know there aren't any string constants in the expression,
otherwise parsing it for beeing dependent on a given variable is much harder.
In my case I generate a local variable VX with some initialization iff the expression
depends on VX.
>
>
> > (LET (())
> >
> > Since I have several such variables I have to do more work to generate
> > of leave out the LET form. It would be nicer if I could generate a
> > No-Op LET form, but I don't know how.
>
> You don't know how to generate () when there are no variable, and how to
> generate ((a x) (b y)) when there are two variables???
>

Yes, that poses some problems to me, as can be seen here

(defun myfct (arg)
(+1 arg))

(defmacro GenFct (This)
(let ((to-let))
(if (search "VX" (format nil "~a" This)) (push `(vx (myfct op)) to-let))
WHAT-TO-BE-PUT-HERE )))
`(defun foo (op)
(let (,to-let) ;; s.t. ,to-let expands to the null string, i.e. I get (let () ...
,This))
))

The alternative solution is to initialize the list after LET to nil and push only those variable declarations I'd like to be there - this works.

But what could I assign to TO-LET to make (,TO-LET) "evaluate" to just () ?

Thanks for your patience.

P.S.
One application is the following

(defmacro AD-Fct (Funct Expr DExpr)
(let* ((ClassS (concatenate 'string "C-" (symbol-name Funct)))
(Class (intern ClassS))
(FCTs (concatenate 'string "AD-" (symbol-name Funct)))
(FCT (intern FCTs)))
`(progn
(defclass ,Class (Term) ((Op :initarg :Op)))
(defgeneric ,FCT (Op))
(defmethod ,FCT ((Op Term))
(make-instance ',Class :Op Op))
(defmethod EVL ((This ,Class) Arg)
(with-slots (Op) This
(let ((EOp (EVL Op Arg)))
,Expr)
))

(defmethod DIFF ((This ,Class) Arg)
(with-slots (Op) This
(let ((EOp (EVL Op Arg)) (DOp (DIFF Op Arg)))
;;; (declare (ignore EOp))
,DExpr)
))))
)

which is used as

(AD-BinOp AD* (* EOpL EOpR) (+ (* DOpL EOpR) (* EOpL DOpR)))

E.g. here, I'd like to suppress the local variable EOpL (including the function call)
if the second expression --- here (+ (* DOpL EOpR) (* EOpL DOpR)) ---
did not depend on EOpL

Kaz Kylheku

4/13/2015 2:29:00 PM

0

On 2015-04-13, jarausch@skynet.be <jarausch@skynet.be> wrote:
> On Monday, 13 April 2015 15:23:05 UTC+2, informatimago wrote:
>> jarausch@skynet.be writes:
>>
>>
>> > meanwhile I've found out that FORMAT can do the conversion.
>>
>> Stop being an idiot!
>
> Thank you for the complements.

Those are compliments; complements are when we flip 1's to 0's, and vice-versa.

Pascal J. Bourguignon

4/13/2015 2:45:00 PM

0

jarausch@skynet.be writes:

>> > Here is what I was looking for
>> >
>> > (defun myfct (arg)
>> > (+1 arg))
>> >
>> > (defmacro GenFct (This)
>> > (let ((to-let
>> > (if (search "VX" (format nil "~a" This)) `(vx (myfct op))
>> > nil)))
>> > `(defun foo (op)
>> > (let (,to-let)
>> > ,This))
>> > ))
>> >
>> > (macroexpand-1 '(GenFct (1+ vx)))
>> >
>> > generates
>> >
>> > (DEFUN FOO (OP)
>> > (LET ((VX (MYFCT OP)))
>> > (1+ VX)))
>> >
>> > Unfortunately, in case the expression does not contain vx
>> > it generates the invalid LET form
>>
>> What does that mean? What is vx? Do:
>>
>> (+ 1 vx)
>>
>> (vx 42)
>>
>> (print "hello vivxen!")
>>
>> (if (= a h)
>> (progn
>> (do-something (concatenate 'string viv #\v #\x en))
>> 'ha)
>> (+ 42 (vx 33)))
>>
>>
>> "contain" vx???
>
> In my case I know there aren't any string constants in the expression,
> otherwise parsing it for beeing dependent on a given variable is much harder.
> In my case I generate a local variable VX with some initialization iff the expression
> depends on VX.

It would be an error to write the macro depending too much on
unspecified assumption, unless you're writing a macrolet.

Maintainers won't necessarily look at the source of your macro, but will
be modifying its applications.

What about cl-user::vx, my-package:vx or your-package:vx?

In anycase, a variable is not a string, so stop searching for
characters, but instead look for a VX symbol naming your variable.

It might be easier to always have the variable,
and (declare (ignorable vx)).

But again if you want to avoid costly initialization you will need to
know if it is really used. And the only way to know it is to use a code
walker. If you used a quick-and-dirty tree search, you would still have
problems with:

(genfct
(let ((vx 24))
(* 2 vx)))

and similar.

The easiest way to avoid having to use a code walker in such a
situation, is to avoid putting yourself in this situation. Instead, let
the caller tell you what variable to use:

(gen-fun (vx) (+ vx (let ((vx 24)) (* 2 vx))))
(let ((vx 33)) (gen-fun () (+ vx (let ((vx 24)) (* 2 vx)))))



>> > (LET (())
>> >
>> > Since I have several such variables I have to do more work to generate
>> > of leave out the LET form. It would be nicer if I could generate a
>> > No-Op LET form, but I don't know how.
>>
>> You don't know how to generate () when there are no variable, and how to
>> generate ((a x) (b y)) when there are two variables???
>>
>
> Yes, that poses some problems to me, as can be seen here

What about:

(mapcar (lambda (variable)
`(,variable 0)) variables)

?


cl-user> (let ((variables (if (zerop (random 2))
'()
'(a))))
`(let ,(mapcar (lambda (variable)
`(,variable 0)) variables)
'hello))
(let nil 'hello)
cl-user> (let ((variables (if (zerop (random 2))
'()
'(a))))
`(let ,(mapcar (lambda (variable)
`(,variable 0)) variables)
'hello))
(let ((a 0)) 'hello)
cl-user>


> One application is the following

(defmacro ad-fct ((&optional evl-variable diff-variable) funct expr dexpr)
(let* ((classs (concatenate 'string "C-" (symbol-name funct)))
(class (intern classs))
(fcts (concatenate 'string "AD-" (symbol-name funct)))
(fct (intern fcts)))
`(progn
(defclass ,class (term) ((op :initarg :op)))
(defgeneric ,fct (op))
(defmethod ,fct ((op term))
(make-instance ',class :op op))
(defmethod evl ((this ,class) arg)
(with-slots (op) this
(declare (ignorable op))
(let (,@(if evl-variable
`((,evl-variable (evl op arg)))
`()))
,expr)))
(defmethod diff ((this ,class) arg)
(with-slots (op) this
(declare (ignorable op))
(let (,@(if evl-variable
`((,evl-variable (evl op arg)))
`())
,@(if diff-variable
`((,diff-variable (diff op arg)))
`()))
,dexpr))))))


cl-user> (pprint (macroexpand-1 '(AD-fct (mickey donald)
AD*
(* mickey EOpR)
(+ (* donald EOpR) (* mickey DOpR)))))

(progn (defclass c-ad* (term) ((op :initarg :op)))
(defgeneric ad-ad* (op))
(defmethod ad-ad* ((op term)) (make-instance 'c-ad* :op op))
(defmethod evl ((this c-ad*) arg)
(with-slots (op)
this
(declare (ignorable op))
(let ((mickey (evl op arg))) (* mickey eopr))))
(defmethod diff ((this c-ad*) arg)
(with-slots (op)
this
(declare (ignorable op))
(let ((mickey (evl op arg)) (donald (diff op arg)))
(+ (* donald eopr) (* mickey dopr))))))
; No value
cl-user> (pprint (macroexpand-1 '(AD-fct ()
AD*
(* mickey EOpR)
(+ (* donald EOpR) (* mickey DOpR)))))

(progn (defclass c-ad* (term) ((op :initarg :op)))
(defgeneric ad-ad* (op))
(defmethod ad-ad* ((op term)) (make-instance 'c-ad* :op op))
(defmethod evl ((this c-ad*) arg)
(with-slots (op)
this
(declare (ignorable op))
(let () (* mickey eopr))))
(defmethod diff ((this c-ad*) arg)
(with-slots (op)
this
(declare (ignorable op))
(let () (+ (* donald eopr) (* mickey dopr))))))
; No value
cl-user>


> E.g. here, I'd like to suppress the local variable EOpL (including the function call)
> if the second expression --- here (+ (* DOpL EOpR) (* EOpL DOpR)) ---
> did not depend on EOpL

Computer says no:

(com.informatimago.common-lisp.cesarum.list:tree-find 'EOpL '(+ (* DOpL EOpR) (* EOpL DOpR)))
--> eopl


--
__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