Hi All,
I came across the following macro function (shortened), but don't know what it should be called or what I should look for to understand more of it.
%macro CIpoisson(cl, x, N, base, rate, ll,lu);
if (&x) < 0 then
do;
&rate = .;
&ll = .;
&lu = .;
end;
else if not(0 < (&cl) < 1) then
do;
&rate = (&base)*(&x)/(&N);
&ll = .;
&lu = .;
end;
else do;
&xx = ...;
end;
%mend;
And it works like
data test;
input obs denominator;
datalines;
-1 100
46 7400
3210 762787
14 400
;
run;
data tempb;
set test;
%cipoiss(0.95,obs,denominator,1000, rate,ll,lu);
run;
It looks like all the variables serve as data holders or reference variables.
Are there any reference books that introduce such macro programmings?
@windlove wrote:
I think my confusion is around
rate, ll, luthese three parameters, in which they are macros, but serve as variable names as well.
Hi @windlove,
In the macro definition (%macro CIpoisson(...)...) these are names of macro parameters (i.e. macro variables). In the macro call (%CIpoisson(...)) these are text strings which happen to coincide with the parameter names (unlike obs vs. x and denominator vs. N) and which are passed as values to those macro variables and eventually used as names of DATA step variables in the DATA step code generated by the macro. Thus the user has the flexibility to choose arbitrary variable names, e.g., UCL for lu. This can be useful, for example, if there was already an existing variable named lu in dataset test so that hardcoding "lu" (instead of "&lu") in the macro code would cause a name conflict.
The developer should have included documentation with his macro.
As it is, we can see that it performs calculations in a data step.
Turn option MPRINT on to see the code generated by the macro in the log.
As for learning the SAS macro language, there are many resources on the web.
The macro here doesn't do a lot, so is a good way to get your toes wet.
It simply adds code to the data step using the values given as parameters.
I think my confusion is around
rate, ll, lu
these three parameters, in which they are macros, but serve as variable names as well.
Because they are doing nothing in the function arguments, but only get updated once the calculation done.
The way how they are being used here looks exactly like pass-by-reference in C++.
If some better formatting rules were used, such as macro language in lower case, and user names (tables variables) in uppercase, the syntax would become more obvious.
data TEMP;
set TEST;
%cipoiss(0.95,OBS,DENOMINATOR,1000, RATE, LL, LU);
run;
You can see that some values are hard-coded, while other values use whatever values are in the variables defined.
This will also be visible in the log in the code generated by option MPRINT.
Looks like, without rate, ll, lu in the macro argument works too. Just wondering whether they are redundant in the original code or there is any benefits to put them there.
%macro cipoiss2(x, D);
if &x < 0 then do;
rate = .;
ll = .;
lu = .;
end;
else do;
rate = &x/&D;
ll = (&x - 1.96*sqrt(&x))/&D;
lu = (&x + 1.96*sqrt(&x))/&D;
end;
%mend;
data tempb;
set test;
%cipoiss2(obs,denominator);
run;
@windlove wrote:
I think my confusion is around
rate, ll, luthese three parameters, in which they are macros, but serve as variable names as well.
Hi @windlove,
In the macro definition (%macro CIpoisson(...)...) these are names of macro parameters (i.e. macro variables). In the macro call (%CIpoisson(...)) these are text strings which happen to coincide with the parameter names (unlike obs vs. x and denominator vs. N) and which are passed as values to those macro variables and eventually used as names of DATA step variables in the DATA step code generated by the macro. Thus the user has the flexibility to choose arbitrary variable names, e.g., UCL for lu. This can be useful, for example, if there was already an existing variable named lu in dataset test so that hardcoding "lu" (instead of "&lu") in the macro code would cause a name conflict.
Maybe it would be less confusing if the macro call used the parameter names in the call. One of the nice features of SAS macros is that you can always use the parameter names in the macro call, even for parameters that the macro has defined such that they can be called by position also.
So your macro call:
%cipoiss(0.95,obs,denominator,1000, rate,ll,lu);
Could be re-written as
%cipoiss
(cl=0.95
,x=obs
,n=denominator
,base=1000
,rate=rate
,ll=ll
,lu=lu
);
So now it is clearer that for the N parameter the user is passing in the variable name DENOMINATOR and for the RATE parameter the user is passing in the variable name RATE.
OK. I understand now.
So they are just normal macro variables.
I think I just didn't expect that variable names in the left-hand side "=" should be changed through function arguments like this.
@windlove wrote:
OK. I understand now.
So they are just normal macro variables.
I think I just didn't expect that variable names in the left-hand side "=" should be changed through function arguments like this.
Modifying the SAS code that you want to run is the whole point of using the macro processor.
SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!
Learn how use the CAT functions in SAS to join values from multiple variables into a single value.
Find more tutorials on the SAS Users YouTube channel.
Ready to level-up your skills? Choose your own adventure.