COMPGROUPS.NET | Search | Post Question | Groups | Stream | About | Register

### Re: %eval in recursive macro #7

• Email
• Follow

Summary: Macro design issues and semicolons
#iw-value=2

Cary,

I agree with Howard that you might learn some interesting things
about macro by reading papers, and with Toby that there are much
better areas in macro to explore than recursion.  However, I do
not ever remember writing a serious macro or a macro for a paper
that involved recursion.  Your question is not really about
recursion or even %EVAL, but it does raise the need for discussing
design issues.

First let's consider a simpler form of the macro.

%macro factorial ( n ) ;
%if &n < 0 %then %put ERROR: NO Negative Numbers ;
%else
%if &n <= 1 %then 1 ;
%else %eval (&n * %factorial(%eval(&n-1))) ;
%mend  factorial ;

This works and protects the macro from calls with negative numbers.
It isn't nice with decimals but at least it doesn't work, and this
lesson is not really about error handling.  But it doesn't answer

>   %macro factorial(n);
>    %if &n GT 1 %then %do;
>     %let next = %factorial(%eval(&n-1));
>     %eval(&n * &next);
>    %end; %else
>    1;
>   %mend;

had a problem with a semicolon and you wanted to know why, when this
fix was suggested.  But first let's consider where the variable NEXT
resides?  Is it global, or local and then which local?  Now in your
case it doesn't matter because you always give a new value to NEXT
and never refer to an old one.  However, since your macro is about
recursion it is particularly important to declare NEXT local.  Then
every executing FACTORIAL has its own copy of that variable in its
own environment for its own use.  As you wrote it there is only one
copy of the variable and it is either in the global environment or
in the environment of the first call to FACTORIAL.  It is not wrong
here, but a dangerous habit to develop and particularly dangerous
in any real recursion situation!

From my point of view, your question should have been - why did the
semicolon work for N=1 and 2, but not 3?  Well, to put it simply,
with 1 the offending semicolon was not relevant, and with 2 it
wasn't tested by your %LET statement.  However, consider:

53   %macro factorial(n);
54    %if &n GT 1 %then %do;
55     %let next = %factorial(%eval(&n-1));
56     %eval(&n * &next) ;
57    %end; %else
58    1;
59   %mend;
60
61   %let x = %factorial(2) + 9 ;
61   %let x = %factorial(2) + 9 ;
--
180
ERROR 180-322: Statement is not valid or it is used out of
proper order.

Now, we see that there was an error for 2; it just wasn't apparent
until one used the value in an expression with text following the
value.  Sometimes when something seems to work and sometimes not,
you can learn more by asking why you thought it worked, because it
makes you more aware of how accidental "working" can be.

Now to answer the question, you have to understand what macros do
in the macro facility.  They generate text to be read by the SAS
compiler.  In its simplest form consider:

62
63   %macro q(n) ;
64      &n ;
65   %mend  q ;
66
67   %let x = %q(2) + 9 ;
67   %let x = %q(2) + 9 ;
--
180
ERROR 180-322: Statement is not valid or it is used out of
proper order.

Ah, the lesson should be generating semicolons in code won't
work when that semicolon splits two parts of a SAS statement
or macro expression such as

%eval(&n*%factorial(&next)

So why did my code work?  Didn't I have semicolons at the end of
every %IF or %ELSE statement?  Well yes, but they belong there!
Macro statements require a semicolon and the macro facility owns
that semicolon, i.e. the expression after the %THEN or %ELSE did
not include a semicolon.  In your case there was no statement so
the semicolon was part of the text generated, not an instruction.

Sticking with almost your macro, you might find the style

%macro factorial(n);
%local next return ;
%if &n GT 1 %then %do;
%let next = %factorial(%eval(&n-1));
%let return = %eval(&n * &next);
%end;
%else
%let return = 1;

&return

%mend factorial ;

This style makes is clear exactly what the macro is generating.
It isn't very good for macros generating SAS statements, but
it is very good for macros generating expressions.  It makes
it very clear what is generated and focuses attention on that
semicolon.

Ian Whitlock
===============

Date:         Mon, 16 Jul 2007 10:56:37 -0400
Reply-To:     Cary Miller <cmiller1@COQIO.SDPS.ORG>
Sender:       "SAS(r) Discussion"
From:         Cary Miller <cmiller1@COQIO.SDPS.ORG>
Subject:      %eval in recursive macro
Hi SAS people,
I am experimenting with basic recursion and having trouble
with
the %eval function.  The macro works for n=1,2 but fails for n=3.
I must be missing something about %eval but not sure what.
Can anybody help shed light on this?
Thanks,
CAM

%macro factorial(n);
%if &n GT 1 %then %do;
%let next = %factorial(%eval(&n-1));
%eval(&n * &next);
%end; %else
1;
%mend;

%let x = %factorial(1);   *OK;
%let x = %factorial(2);   *OK;
%let x = %factorial(3);   *ERROR;

/*ERROR: A character operand was found in the %EVAL function or
%IF
condition where a numeric*/
/*       operand is required. The condition was: 3 * 2;*/
/*ERROR: The macro FACTORIAL will stop executing.*/

 0
Reply iw1junk (1195) 7/17/2007 8:24:00 PM

See related articles to this posting

0 Replies
55 Views

Similar Articles

12/11/2013 9:23:23 PM
[PageSpeed]

Similar Artilces:

Re: macro #7
> From: helen [mailto:chenghelen2000@YAHOO.COM] > I wrote a nasty macro as following, here are the questions > > 1.what are the difference between using a inline macro and > using a macro call. The results are going to be the same; my point would be: which is easier to read, comprehend and ultimately adjust, or make do something slightly different? part of readability is whether the sub-routines are defined in the program or are stored outside of it. The macro language is not a programming language so your example here illustrates some not necessarily good macro programming s...

Re: Macro [ab]usage (was: (OT) old style macro is still working) #2 #7
Don't forget the elegant macro-based access to the dictionary meta-data with SQL Select Into - functionality only accessible via SAS Macro. Paul Choate DDS Data Extraction (916) 654-2160 -----Original Message----- From: SAS(r) Discussion [mailto:SAS-L@LISTSERV.UGA.EDU] On Behalf Of Paul M. Dorfman Sent: Monday, June 14, 2004 10:52 AM To: SAS-L@LISTSERV.UGA.EDU Subject: Re: Macro [ab]usage (was: (OT) old style macro is still working) Quentin McMullen, in part wrote: > So to rename a group of variables, I can code: > > data b; > set a (rename=(%rename(x y z,prefix=_))); run...

Re: Macro array question #7
Subject: Macro array question Summary: Important question of SAS events timing Respondent: IanWhitlock@westat.com Venita [depuy001@DCRI.DUKE.EDU] has asked an important question about the timing of events timing in SAS. Moreover, she has indicated an interest and need for understanding what is going on, so let me simplify by explaining the problem in more general terms. You have a set of macro variables, probably many, with fixed values, i.e., they do not change within the DATA step. Now the problem is to import these values into data variables. How should it be done. For example, %le...

Re: Scope of Macro Variables #7
> From: Roger DeAngelis [mailto:xlr82sas@AOL.COM] > I am considering adding the following line of code to all > my macros > > %Local CreateLocalSymbolTable; nice rhetorical statement. consider: %macro NoParms(_=the name of this macro is false); %let localA = a;%let localB=bb; %Put _local_;%mend; %NoParms(); \begin{soapbox} imnsho, you're always asking for more trouble than you're worth when you write a macro without a parameter list. In any production code which macro returns SAS code then a macro without parameters -should- be an %Include there's no need for ...

Re: macro challenge: recursion #2
> From: Chang Y. Chung > This fixed it, but I don't know why. :-/ > > OLD> %hexDigit(%eval(&N. - (&Ndiv.*16)))%Mend; > NEW> %*;%hexDigit(%eval(&N. - (&Ndiv.*16)))%Mend; well, you're halfway there: one point for solution now to figure out what your solution did for the code. clue: the problem is 'invisible' I do have one complete solution in private e-mail I'll wait till tomorrow to post reason and solution to give more people time to cogitate. its a very back-of-hand-to-forehead trick! Ron Fehd the macro maven CDC Atlanta GA USA...

Re: Macros for recursive subroutine in data step
Hi, Here are all five examples (including previous two) of using my data step recursive subroutine macros. All the examples are bundled in a macro called test. Enjoy! Cheers, Chang <sasl:code> %macro test(what); %let what=%upcase(&what.); %if &what.= %then %let what=; %*-- test1 -- calc factorial by multiplication --*; %if &what.=_ALL_ or %index(&what.,1) %then %do; data _null_; %sub_init(foo, m level) f = 1; %sub_call(foo, 12 1) put "12!=" f; stop; %sub_do(foo) put level=; if m>1 then do; f = m*f; m + (...

Re: iterative %do loop in macro language #7
I know you really like to compute the stop value for your %DO as you have a aversion to %WHILE not blank. I was wondering why you don't use COUNTW. Because it is not documented? 80 %Macro Iter(List=,dlm=%str( )); 81 %Local I Stop ; 82 /* %Let Stop = %Eval( %SysFunc( CountC( &List , %Str( ) ) ) + ( 82 ! %Length( &List) > 0 ) ) ;*/ 83 %let Stop = %Sysfunc(countw(%bquote(&list),&dlm)); 84 %Do I = 1 %To &Stop; 85 %Put NOTE: Item=%Scan(%bquote(&List),&I,&dlm); 86 %End; 87 %Mend Iter; 88 %Iter(List=import export conf...

Re: Recursive assignments in macro #9 690713
datanull@GMAIL.COM replied to Toby, >On 6/12/07, toby dunn <tobydunn@hotmail.com> wrote: >>Jue , >> >>All you are doing is making a huge nightmare worse by doing this, >>basically >>your slowly wrapping an enigma inside a riddle covered by a illusion. > >Your doomsday scenario is too extreme. The problem hardly seems >complex at all. > >count from 1 by 1 >select word(n) and word(n+1) while word(n+1) is not blank >do something with the words. > >One might argue that, what is being done with the words is a bit >disconcerting. ...

Re: Possible to replace validation code with macro call? #7
Yes that's about the size of it. Anyhow, your suggestion worked and is much appreciated. :-D -----Original Message----- From: toby dunn [mailto:tobydunn@hotmail.com] Sent: 04 May 2007 16:01 To: Ben Powell; SAS-L@LISTSERV.UGA.EDU Subject: Re: Possible to replace validation code with macro call? Ahh you want some weird hybrid of actual values well dont know why you want this Ben but cool have fun with it my man. Toby Dunn You can see a lot by just looking. ~Yogi Berra Do not seek to follow in the footsteps of the wise. Seek what they sought. ~Matsuo Basho You never know what is en...

Re: One of my reporting macros has 90 parameters
On Tue, 31 Jan 2006 06:17:28 -0800, RolandRB <rolandberry@HOTMAIL.COM> wrote: >One of my reporting macros has 90 parameters. Is that a record? Any >advance on 90? would it not be simpler and more maintainable for the reporting process to be written without the 90 parameter macro ? And in the area of on-going support & documentation, I have a lot more respect for SI documentation than anyone-elses. Peter ...

Re: Using a macro variable in a "where" clause #7 627489
Thank you all for the help. I could surely use some of the coding techniques you sent me. Ron was very keen to notice the double quotes contained in the macro variable that I was trying to pass, and which was giving me the problem. No, Harry, I'm not trying to get away from macro- ing...I'm trying to learn it. Chang, the macro (in my code), when no item was checked, passed nothing so I have to define the response as to how the data step should handle such a case (which is, NOT to filter for the variable at all). Jose ...

Re: [LogoForum] Re: dynamic scope #7
The message below is being cross-posted from LogoForum. One more example about ASK-CALLER (note, ASK is a command, CALLER is a function, so they are separate things) The next example is from Elica's help about CALLER: to ifnot :condition :commands if not :condition [ask caller :commands] end make "a 5 make "b 10 make "c 100 ifnot (:a<:b) [make "c :a+:b] print :c ; -> 100 ifnot (:a>:b) [make "c :a-:b] print :c ; -> -5 LogoForum messages are archived at: http://groups.yahoo.com/group/LogoForum ...

Re: Explanation of macros; Haskell macros #2
{newsgroup list trimmed} >> "Anton van Straaten" <anton@appsolutions.com> writes: > >>>Yes, but the point is that with a concise syntax for lambda, entire >>>classes of macros can become unnecessary. That's how Smalltalk >>>handles 'if', for example - no macros or special forms needed. I keep hearing good (or at least interesting) things about Smalltalk. But back when I looked at it, I was really unimpressed by its community. The mood is generally like "Yeah, Smalltalk is dead, let's finish the projects we are working...

Re: The LOOP macro (was Re: Be afraid of XML)
John Thingstad wrote: > The C loop is more simular to do. > Think a cobol loop to find simular functionality. There you have it, folks. CL is COBOL-Like. > > > David Steuber <david.steu...@verizon.net> wrote: > > >> The C for loop is so much simpler for me to understand. > > > That's hardly surprising. It performs a simple task, and has a very > > simple syntax. LOOP tries to accomplish much more, and needs to be more > complex as a result. ...

Re: SUSPECT: Re: Idea for a collaborative talk
Perhaps it could be done without macros , example: proc sql; create table parameters as select distinct age from sashelp.class; quit; data _null_; do until (EoF); set parameters end=EoF; call symput('a',strip(age)); call execute(' proc summary data=sashelp.class (where=(age=&a)) nway; class age sex; var height weight; output out= age&a._stats (drop=_:) sum()= /autoname; run;'); end; run; Daniel Fernandez Barcelona -----Mensaje original----- De: SAS(r) Discussion [mailto:SAS-L@LISTSERV.UGA.EDU] En nombre de Peter Flom Enviado el: martes, 17 de noviembre de 200...

Re: [VMS 7.3-2] UPDATE ECO 7 is out
If you would run \$PRODUCT LIST VMS732_UPDATE answer the questions and check the ".RELEASE_NOTES" files, you could tell us. peter@langstoeger.at (Peter 'EPLAN' LANGSTOEGER) wrote on 06/20/2006 11:23:27 AM: > As you may already have noticed, the quarterly wave of UPDATE ECOs arrived. > And I already found discrepancies. > > eg. > ftp://ftp.itrc.hp.com/openvms_patches/alpha/V7. > 3-2/ALPHA_V732_MASTER_ECO_LIST.txt > states that VMS732_LOADSS-V0200 is included/superceded by UPDATE V7 while > ftp://ftp.itrc.hp.com/openvms_patches/alpha/V7.3-2/VMS732_UPDA...

Re: macros
mikel wrote: > Where else do you see unwind-protect? > > I ran into this problem a lot of times working on large projects using > Lisp--the problem of explaining why Lisp was a good choice for > implementing what I was doing. We would be asked what it gave us, and > would give an answer, and the questioners would say "but I could do that > with <insert language here>." [snip...] > I think a really interested person could learn a lot of what makes Lisp > special just by looking at how many and what kinds of things are > idiomatic in Lisp projects t...

Re: new to macros, need help!! re-post. #5 623127
dude: Classic mistake in queries of dictionary.<whatever> .... SQL comparisons case sensitive .... In such situations, UPCASE(libname)='XX' will always succeed when it should. Same for memname and name.... Sig -----Original Message----- From: dude [mailto:dude@DUDES.COM] Sent: Friday, October 17, 2003 10:54 AM To: SAS-L@LISTSERV.UGA.EDU Subject: Re: new to macros, need help!! re-post. Ian, I tried your snippet: the proc sql did not select any columns :-( I know for a fact that the columns are there. I don't know enough about the proc sql to even attempt to fix it. Did I...

Re: Macro Variable w. Another Macro Variable in name #3
Does the following describe what you are now trying to do? %macro testidea; %let myarray=XX XY YY; %do i=1 %to 3; %let s0=%scan(&myarray,&i); %let count&s0=0; %put &&count&s0; %let count&s0=%sysevalf(&&count&s0+1); %put &&count&s0; %end; %mend; %testidea HTH, Art --------- On Fri, 19 Jan 2007 08:14:41 -0600, OR Stats <stats112@GMAIL.COM> wrote: >Hi Arthur and all, > >It's getting closer thankfully. The code below works. However, when I try >to make this macro variable (that has another ma...

Re: new to macros, need help!! re-post. #5 1540440
Dom, I see that Ken Moody explained the real issue with your program. I'd just like to point out that you can completely eliminate your first DATA step by a little recoding of your PROC CONTENTS as follows. Proc contents data=se.test(keep=chp:) out=memlist(keep=name) noPrint ; Run ; Ed Edward Heaton, Senior Systems Analyst, Westat (An Employee-Owned Research Corporation), 1600 Research Boulevard, Room RW-3541, Rockville, MD 20850-3195 Voice: (301) 610-4818 Fax: (301) 610-5128 mailto:EdHeaton@westat.com http://www.westat.com -----Origi...