Administrator
|
Gene commented on an earlier thread mentioning that my posts sometimes use recursion.
I replied that they didn't and that SPSS didn't really support recursion. After a bit of screwing around I came up with an example of a simple recursive MACRO. UNFORTUNATELY: I can't think of any way to do anything useful with the concept ;-( If I could come up with something useful there would undoubtedly be more efficient ways of implementing any resulting algorithm (iterative). Kirill????? --- DEFINE RECURSE (!POS !TOKENS(1)). !IF (!LENGTH(!1) !LT 99) !THEN !LET !X=!CONCAT(!1,"X") !CONCAT (RECURSE," ",!X) . ECHO !QUOTE (!1). !IFEND !ENDDEFINE. SET MNEST 100. RECURSE X . -Output- XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXX XXXXXXXXXXXXXX XXXXXXXXXXXXX XXXXXXXXXXXX XXXXXXXXXXX XXXXXXXXXX XXXXXXXXX XXXXXXXX XXXXXXX XXXXXX XXXXX XXXX XXX XX X
Please reply to the list and not to my personal email.
Those desiring my consulting or training services please feel free to email me. --- "Nolite dare sanctum canibus neque mittatis margaritas vestras ante porcos ne forte conculcent eas pedibus suis." Cum es damnatorum possederunt porcos iens ut salire off sanguinum cliff in abyssum?" |
Administrator
|
You wanted examples of posts that sent me to the FM. See below!
This is from the FM entry for SET: Macro Displays. You can use the MEXPAND, MITERATE, and MNEST subcommands to control macro expansion, the maximum number of loop iterations, and nesting levels within a macro. You can also use the MPRINT subcommands to control the display of the variables, commands, and parameters that a macro uses. p.s. - I can see that macro (and variations thereon) being used to produce ASCII art.
--
Bruce Weaver bweaver@lakeheadu.ca http://sites.google.com/a/lakeheadu.ca/bweaver/ "When all else fails, RTFM." PLEASE NOTE THE FOLLOWING: 1. My Hotmail account is not monitored regularly. To send me an e-mail, please use the address shown above. 2. The SPSSX Discussion forum on Nabble is no longer linked to the SPSSX-L listserv administered by UGA (https://listserv.uga.edu/). |
Administrator
|
OK Bruce,
I don't want to see any green junk flying after your head stops spinning ;-))) LOL DEFINE RECURSE (!POS !TOKENS(1) /!POS !TOKENS(1) / !POS !CMDEND). !IF (!TAIL(!3) !NE !NULL) !THEN !1 !HEAD(!3) !2 !TAIL(!3) . RECURSE !1 !2 !TAIL(!3) . !IFEND !ENDDEFINE. SET MNEST 100. DATA LIST FREE /A B C D E F G H I J K L M . BEGIN DATA 1 1 5 3 1 3 6 1 5 3 1 5 3 6 2 6 1 5 3 2 5 3 6 5 2 3 5 1 2 5 6 3 5 1 5 3 6 2 5 3 2 1 5 3 6 1 2 5 3 1 2 5 3 5 6 1 2 5 6 3 7 3 5 1 2 4 5 6 3 2 6 7 5 3 1 2 3 4 END DATA. RECURSE CROSSTABS BY A B C D E F G H I J K L M. RECURSE CORRELATION WITH A B C D E F G H I J K L M.
Please reply to the list and not to my personal email.
Those desiring my consulting or training services please feel free to email me. --- "Nolite dare sanctum canibus neque mittatis margaritas vestras ante porcos ne forte conculcent eas pedibus suis." Cum es damnatorum possederunt porcos iens ut salire off sanguinum cliff in abyssum?" |
Administrator
|
For the benefit of those who don't have a current SPSS license (or who just have not bothered to run the syntax), here is what David's magical macro generates (obtained by setting MPRINT ON before running the macros):
SET MPRINT ON. RECURSE CROSSTABS BY A B C D E F G H I J K L M. 2144 0 M> 2145 0 M> . 2146 0 M> CROSSTABS A BY B C D E F G H I J K L M. 2147 0 M> 2148 0 M> . 2149 0 M> CROSSTABS B BY C D E F G H I J K L M. 2150 0 M> 2151 0 M> . 2152 0 M> CROSSTABS C BY D E F G H I J K L M. 2153 0 M> 2154 0 M> . 2155 0 M> CROSSTABS D BY E F G H I J K L M. 2156 0 M> 2157 0 M> . 2158 0 M> CROSSTABS E BY F G H I J K L M. 2159 0 M> 2160 0 M> . 2161 0 M> CROSSTABS F BY G H I J K L M. 2162 0 M> 2163 0 M> . 2164 0 M> CROSSTABS G BY H I J K L M. 2165 0 M> 2166 0 M> . 2167 0 M> CROSSTABS H BY I J K L M. 2168 0 M> 2169 0 M> . 2170 0 M> CROSSTABS I BY J K L M. 2171 0 M> 2172 0 M> . 2173 0 M> CROSSTABS J BY K L M. 2174 0 M> 2175 0 M> . 2176 0 M> CROSSTABS K BY L M. 2177 0 M> 2178 0 M> . 2179 0 M> CROSSTABS L BY M. 2180 0 M> RECURSE CORRELATION WITH A B C D E F G H I J K L M. 2196 0 M> 2197 0 M> . 2198 0 M> CORRELATION A WITH B C D E F G H I J K L M. 2199 0 M> 2200 0 M> . 2201 0 M> CORRELATION B WITH C D E F G H I J K L M. 2202 0 M> 2203 0 M> . 2204 0 M> CORRELATION C WITH D E F G H I J K L M. 2205 0 M> 2206 0 M> . 2207 0 M> CORRELATION D WITH E F G H I J K L M. 2208 0 M> 2209 0 M> . 2210 0 M> CORRELATION E WITH F G H I J K L M. 2211 0 M> 2212 0 M> . 2213 0 M> CORRELATION F WITH G H I J K L M. 2214 0 M> 2215 0 M> . 2216 0 M> CORRELATION G WITH H I J K L M. 2217 0 M> 2218 0 M> . 2219 0 M> CORRELATION H WITH I J K L M. 2220 0 M> 2221 0 M> . 2222 0 M> CORRELATION I WITH J K L M. 2223 0 M> 2224 0 M> . 2225 0 M> CORRELATION J WITH K L M. 2226 0 M> 2227 0 M> . 2228 0 M> CORRELATION K WITH L M. 2229 0 M> 2230 0 M> . 2231 0 M> CORRELATION L WITH M. 2232 0 M> SET MPRINT OFF. 2248 0 M> SET MPRINT OFF. That's pretty slick. ;-)
--
Bruce Weaver bweaver@lakeheadu.ca http://sites.google.com/a/lakeheadu.ca/bweaver/ "When all else fails, RTFM." PLEASE NOTE THE FOLLOWING: 1. My Hotmail account is not monitored regularly. To send me an e-mail, please use the address shown above. 2. The SPSSX Discussion forum on Nabble is no longer linked to the SPSSX-L listserv administered by UGA (https://listserv.uga.edu/). |
Bruce, thanks for posting the expansion.
David, thanks for imagining and illustrating what is possible. Gene Maguin -----Original Message----- From: SPSSX(r) Discussion [mailto:[hidden email]] On Behalf Of Bruce Weaver Sent: Monday, December 09, 2013 4:40 PM To: [hidden email] Subject: Re: Recursion with Macro ;-) For the benefit of those who don't have a current SPSS license (or who just have not bothered to run the syntax), here is what David's magical macro generates (obtained by setting MPRINT ON before running the macros): SET MPRINT ON. RECURSE CROSSTABS BY A B C D E F G H I J K L M. 2144 0 M> 2145 0 M> . 2146 0 M> CROSSTABS A BY B C D E F G H I J K L M. 2147 0 M> 2148 0 M> . 2149 0 M> CROSSTABS B BY C D E F G H I J K L M. 2150 0 M> 2151 0 M> . 2152 0 M> CROSSTABS C BY D E F G H I J K L M. 2153 0 M> 2154 0 M> . 2155 0 M> CROSSTABS D BY E F G H I J K L M. 2156 0 M> 2157 0 M> . 2158 0 M> CROSSTABS E BY F G H I J K L M. 2159 0 M> 2160 0 M> . 2161 0 M> CROSSTABS F BY G H I J K L M. 2162 0 M> 2163 0 M> . 2164 0 M> CROSSTABS G BY H I J K L M. 2165 0 M> 2166 0 M> . 2167 0 M> CROSSTABS H BY I J K L M. 2168 0 M> 2169 0 M> . 2170 0 M> CROSSTABS I BY J K L M. 2171 0 M> 2172 0 M> . 2173 0 M> CROSSTABS J BY K L M. 2174 0 M> 2175 0 M> . 2176 0 M> CROSSTABS K BY L M. 2177 0 M> 2178 0 M> . 2179 0 M> CROSSTABS L BY M. 2180 0 M> RECURSE CORRELATION WITH A B C D E F G H I J K L M. 2196 0 M> 2197 0 M> . 2198 0 M> CORRELATION A WITH B C D E F G H I J K L M. 2199 0 M> 2200 0 M> . 2201 0 M> CORRELATION B WITH C D E F G H I J K L M. 2202 0 M> 2203 0 M> . 2204 0 M> CORRELATION C WITH D E F G H I J K L M. 2205 0 M> 2206 0 M> . 2207 0 M> CORRELATION D WITH E F G H I J K L M. 2208 0 M> 2209 0 M> . 2210 0 M> CORRELATION E WITH F G H I J K L M. 2211 0 M> 2212 0 M> . 2213 0 M> CORRELATION F WITH G H I J K L M. 2214 0 M> 2215 0 M> . 2216 0 M> CORRELATION G WITH H I J K L M. 2217 0 M> 2218 0 M> . 2219 0 M> CORRELATION H WITH I J K L M. 2220 0 M> 2221 0 M> . 2222 0 M> CORRELATION I WITH J K L M. 2223 0 M> 2224 0 M> . 2225 0 M> CORRELATION J WITH K L M. 2226 0 M> 2227 0 M> . 2228 0 M> CORRELATION K WITH L M. 2229 0 M> 2230 0 M> . 2231 0 M> CORRELATION L WITH M. 2232 0 M> SET MPRINT OFF. 2248 0 M> SET MPRINT OFF. That's pretty slick. ;-) David Marso wrote > OK Bruce, > I don't want to see any green junk flying after your head stops > spinning > ;-))) > LOL > > DEFINE RECURSE (!POS !TOKENS(1) /!POS !TOKENS(1) / !POS !CMDEND). > !IF (!TAIL(!3) !NE !NULL) !THEN > !1 !HEAD(!3) !2 !TAIL(!3) . > RECURSE !1 !2 !TAIL(!3) . > !IFEND > !ENDDEFINE. > > SET MNEST 100. > DATA LIST FREE /A B C D E F G H I J K L M . > BEGIN DATA > 1 1 5 3 1 3 6 1 5 3 1 5 3 > 6 2 6 1 5 3 2 5 3 6 5 2 3 > 5 1 2 5 6 3 5 1 5 3 6 2 5 > 3 2 1 5 3 6 1 2 5 3 1 2 5 > 3 5 6 1 2 5 6 3 7 3 5 1 2 > 4 5 6 3 2 6 7 5 3 1 2 3 4 > END DATA. > RECURSE CROSSTABS BY A B C D E F G H I J K L M. > RECURSE CORRELATION WITH A B C D E F G H I J K L M. ----- -- Bruce Weaver [hidden email] http://sites.google.com/a/lakeheadu.ca/bweaver/ "When all else fails, RTFM." NOTE: My Hotmail account is not monitored regularly. To send me an e-mail, please use the address shown above. -- View this message in context: http://spssx-discussion.1045642.n5.nabble.com/Recursion-with-Macro-tp5723537p5723547.html Sent from the SPSSX Discussion mailing list archive at Nabble.com. ===================== To manage your subscription to SPSSX-L, send a message to [hidden email] (not to SPSSX-L), with no body text except the command. To leave the list, send the command SIGNOFF SPSSX-L For a list of commands to manage subscriptions, send the command INFO REFCARD ===================== To manage your subscription to SPSSX-L, send a message to [hidden email] (not to SPSSX-L), with no body text except the command. To leave the list, send the command SIGNOFF SPSSX-L For a list of commands to manage subscriptions, send the command INFO REFCARD |
Administrator
|
Sure Gene,
You lit the fire ;-) It is interesting to compare the RECURSIVE version to an ITERATIVE one. They both punch out the same code but somehow the RECURSE macro seems much tidier/elegant than the ITERATE macro DEFINE RECURSE (!POS !TOKENS(1) /!POS !TOKENS(1) / !POS !CMDEND). !IF (!TAIL(!3) !NE !NULL) !THEN !1 !HEAD(!3) !2 !TAIL(!3) . RECURSE !1 !2 !TAIL(!3) . !IFEND !ENDDEFINE. RECURSE CROSSTABS BY A B C D E F G H I J K L M. DEFINE ITERATE (!POS !TOKENS(1) /!POS !TOKENS(1) / !POS !CMDEND). !LET !Cpy=!3 !DO !H !IN (!TAIL(!3)) !1 !HEAD(!Cpy) !2 !TAIL(!Cpy). !LET !Cpy=!TAIL(!Cpy) !DOEND !ENDDEFINE. ITERATE CROSSTABS BY A B C D E F G H I J K L M.
Please reply to the list and not to my personal email.
Those desiring my consulting or training services please feel free to email me. --- "Nolite dare sanctum canibus neque mittatis margaritas vestras ante porcos ne forte conculcent eas pedibus suis." Cum es damnatorum possederunt porcos iens ut salire off sanguinum cliff in abyssum?" |
Administrator
|
More fun.
Passing an arbitrary macro name as a parameter to a macro which recursively parses two lists in parallel and invokes the macro with the appropriate set of paired values from the lists ;-) Note that DoSomething and DoSomethingElse could be arbitrarily complex (include OMS, complex data smashing etc). Bzzzt! DEFINE DoSomething (!POS !CMDEND). CORRELATION !HEAD(!1) WITH !TAIL(!1) . !ENDDEFINE . DEFINE DoSomethingElse (!POS !CMDEND). ONEWAY !HEAD(!1) BY !TAIL(!1) . !ENDDEFINE . DEFINE Parallel (!POS !CHAREND ("/") / !POS !CHAREND ("/") / !POS !CMDEND ). !UNQUOTE(!1) !HEAD(!2) !HEAD(!3) . !IF (!TAIL(!2) !NE !NULL) !THEN Parallel !1 / !TAIL(!2) / !TAIL(!3). !IFEND !ENDDEFINE. DATA LIST FREE / a b c d e f. BEGIN DATA 1 2 3 2 3 4 5 6 7 8 9 1 2 3 4 5 1 2 3 3 5 6 7 8 END DATA. Parallel 'DoSomething' /a b c /d e f. Parallel 'DoSomethingElse' /a b c /d e f.
Please reply to the list and not to my personal email.
Those desiring my consulting or training services please feel free to email me. --- "Nolite dare sanctum canibus neque mittatis margaritas vestras ante porcos ne forte conculcent eas pedibus suis." Cum es damnatorum possederunt porcos iens ut salire off sanguinum cliff in abyssum?" |
At 11:51 AM 12/11/2013, David Marso wrote:
>More fun: Passing an arbitrary macro name as a parameter to a macro >which recursively parses two lists in parallel and invokes the macro >with the appropriate set of paired values from the lists ;-) [Definitions of the argument macros omitted] >DEFINE Parallel > (!POS !CHAREND ("/") / !POS !CHAREND ("/") / !POS !CMDEND ). >!UNQUOTE(!1) !HEAD(!2) !HEAD(!3) . >!IF (!TAIL(!2) !NE !NULL) !THEN >Parallel !1 / !TAIL(!2) / !TAIL(!3). >!IFEND >!ENDDEFINE. That's a nice job, and a nice way to step in parallel through two lists. (Direct implementation using "!DO !varname !IN (list)" is awkward: !DO, unlike DO REPEAT, which it resembles, cannot directly step through multiple lists in parallel, requiring !HEAD/!TAIL code to handle all but the first list.) In computer-science terminology, your method here is not true recursion, but what is called tail-recursion: A program calls itself, but only as its last act before terminating. It's fundamentally easier to implement than is true recursion, because it doesn't require that the first instance's local data be preserved separate from the second instance's version of the same data. Tail-recursion can always be replaced by a loop, unlike, say, >Fib(n)=Fib(n-1)+Fib(n-2) >Fib(1)=Fib(2)=1 I don't think true recursion is possible in SPSS macros, because they have no local storage -- I've looked, and I think all your examples are effectively tail-recursion. But that's a nice addition to the armory of SPSS macro-coding techniques. ===================== To manage your subscription to SPSSX-L, send a message to [hidden email] (not to SPSSX-L), with no body text except the command. To leave the list, send the command SIGNOFF SPSSX-L For a list of commands to manage subscriptions, send the command INFO REFCARD |
Administrator
|
"I don't think true recursion is possible in SPSS macros, because they
have no local storage -- I've looked, and I think all your examples are effectively tail-recursion. But that's a nice addition to the armory of SPSS macro-coding techniques. " Thanks for your kind words Richard. Does the very first example at the beginning of the thread count? I am unclear as to what the macro has as far as storage in something like this. Notice the 'ascii art' starts LONG and shrinks as successive calls 'pop' off the stack. Notice without MNEST set adequately it will fail with a stack error. I am not versed in comp sci so would not be the person to ask. OTOH: I believe this to be a neat development in my own incurable macro-philia. Just when I thought there was nothing left to play with in macro I get bit on the brain by this thing ;-)
Please reply to the list and not to my personal email.
Those desiring my consulting or training services please feel free to email me. --- "Nolite dare sanctum canibus neque mittatis margaritas vestras ante porcos ne forte conculcent eas pedibus suis." Cum es damnatorum possederunt porcos iens ut salire off sanguinum cliff in abyssum?" |
Administrator
|
The more I reflect the more I am convinced that when the macro invokes the recursive call it is the same as if it were calling a completely different macro (i.e. all existing internal values are preserved until the return). How could it be otherwise? After all, it's not as though they have self awareness or anything ;-)
So all the goodies are on the stack until the whole thing unwinds.
Please reply to the list and not to my personal email.
Those desiring my consulting or training services please feel free to email me. --- "Nolite dare sanctum canibus neque mittatis margaritas vestras ante porcos ne forte conculcent eas pedibus suis." Cum es damnatorum possederunt porcos iens ut salire off sanguinum cliff in abyssum?" |
Administrator
|
In reply to this post by Richard Ristow
Here is an incredibly inefficient 'recursive?' MACRO implementation of Richard's Fib (Fibonacci sequence for those scratching their heads). Of course one should NEVER actually use this code.Â
It is merely an example of another macro which plays with itself ;-)
This is akin to gluing together millions/billions of dung-bricks using spit and dirt and then measuring the result by pacing toe to foot while using a walker with one broken arm (while drunk ) while being pursued by an angry nest of army ants and a swarm of Africanized bees.
note that Fib 47 results in a final chunk of dung almost 3 billion units long -The fact that SPSS can assemble a string that large ?quickly? is most impressive-. Too bad nobody ever taught macro basic math
* n1 n2 fibn it X * . * n1 n2 fibn it X * . DEFINE FibHelper  (!POS !TOKENS(1)/!POS !TOKENS(1)/!POS !TOKENS(1)/!POS !TOKENS(1)). !LET !IT   = !LENGTH(!CONCAT(!BLANKS(1 ),!BLANKS(!3))) !LET !FibN = !LENGTH(!CONCAT(!BLANKS(!1),!BLANKS(!2))) !IF (!IT !NE !4) !THEN fibhelper !2 !FibN !IT !4 !ELSE ECHO !QUOTE(!FibN) . !IFEND !ENDDEFINE. DEFINE fib (!POS !TOKENS(1)). PRESERVE. SET MNEST=!1. FibHelper 0 1 1 !1 RESTORE. !ENDDEFINE . SET MPRINT OFF .
Fib 47. Fib 47. 2,971,215,073 DEFINE Fib_Matrix (!POS !TOKENS(1)). PRESERVE. SET MXLOOPS !1 . MATRIX. COMPUTE FibX=MAKE(!1,1,1). LOOP #=3 TO !1. COMPUTE FibX(#)=FibX(#-2)+FibX(#-1). END LOOP. PRINT FibX(!1) /FORMAT "F40.0". END MATRIX. RESTORE. !ENDDEFINE. Fib_Matrix 180. On Wed, Dec 11, 2013 at 3:21 PM, Richard Ristow [via SPSSX Discussion] <[hidden email]> wrote:
Please reply to the list and not to my personal email.
Those desiring my consulting or training services please feel free to email me. --- "Nolite dare sanctum canibus neque mittatis margaritas vestras ante porcos ne forte conculcent eas pedibus suis." Cum es damnatorum possederunt porcos iens ut salire off sanguinum cliff in abyssum?" |
In reply to this post by David Marso
At 03:57 AM 12/12/2013, David Marso wrote:
>The more I reflect the more I am convinced that when the macro >invokes the recursive call it is the same as if it were calling a >completely different macro (i.e. all existing internal values are >preserved until the return). How could it be otherwise? It could be otherwise very easily, and is in many programming systems. Some programming environments have a single 'name space'. In those, a name (say, "A") always refers to the same entity, no matter where in the code it appears; no values are 'internal' to a procedure. And in many others, names are local to procedures but not to instances of those procedures. In both cases, if a procedure calls itself, the called instance may change the caller's internal values. The SPSS macro environment couldn't well follow the first of those models, since macro variables can't exist except within a macro; but I'd assumed it would follow the second. Interestingly (and undocumentedly) it does not, but binds variables to each *instance* of a macro invocation; see David's examples, or Example II, below. SPSS macros apparently can't 'see' variables belonging to macros that call them, even when they have no variables with the same name; see both examples. (Thus, until David Marso thinks of a way -- how's that for confidence? -- a macro can't return values to its caller. So, alas, a macro like "Plus", to take two arguments and return their sum, appears impossible.) One very strange quirk: If a macro calls a *different* macro, variables named in the calling macro are undefined (until assigned) in the macro called; but if a macro calls *itself*, variables named in the caller are defined, but blank, in the called instance: compare the values of !B in the called macros, in the two examples. * Test of preservation of macro-variable values across calls: . * Example I: A macro calls a different macro: . DEFINE !Outer() ECHO 'Starting macro "<!>Outer":'. !LET !A = 'Alpha' !LET !B = 'Beta' ECHO !QUOTE(!CONCAT('A = ',!A)). ECHO !QUOTE(!CONCAT('B = ',!B)). !Inner ECHO 'Back from the call to "<!>Inner":', ECHO !QUOTE(!CONCAT('Depth = ',!Depth)). ECHO !QUOTE(!CONCAT('A = ',!A)). ECHO !QUOTE(!CONCAT('B = ',!B)). !ENDDEFINE. DEFINE !Inner() !LET !A = 'Gamma' ECHO 'In the macro "<!>Inner":'. ECHO !QUOTE(!CONCAT('A = ',!A)). ECHO !QUOTE(!CONCAT('B = ',!B)). !ENDDEFINE. !Outer. Starting macro "<!>Outer": A = Alpha B = Beta In the macro "<!>Inner": A = Gamma B = !B Back from the call to "<!>Inner": A = Alpha B = Beta * Example II: A macro calls itself (i.e., a recursive call): . DEFINE !Cursive (Depth=!TOKENS(1)) !IF (!Depth !LT 2) !THEN !LET !A = 'Alpha' !LET !B = 'Beta' ECHO !QUOTE(!CONCAT('Depth = ',!Depth)). ECHO !QUOTE(!CONCAT('A = ',!A)). ECHO !QUOTE(!CONCAT('B = ',!B)). !Cursive Depth = 2 ECHO 'Back from the recursive call:', ECHO !QUOTE(!CONCAT('Depth = ',!Depth)). ECHO !QUOTE(!CONCAT('A = ',!A)). ECHO !QUOTE(!CONCAT('B = ',!B)). !IFEND !IF (!Depth !GE 2) !THEN !LET !A = 'Gamma' ECHO 'In the recursive instance:'. ECHO !QUOTE(!CONCAT('Depth = ',!Depth)). ECHO !QUOTE(!CONCAT('A = ',!A)). ECHO !QUOTE(!CONCAT('B = ',!B)). !IFEND !ENDDEFINE. !Cursive Depth=1. Depth = 1 A = Alpha B = Beta In the recursive instance: Depth = 2 A = Gamma B = Back from the recursive call: A = Alpha B = Beta =================== APPENDIX: Test code =================== * C:\Documents and Settings\Richard\My Documents . * \Technical\spssx-l\Z-2013\ . * 2013-12-12 Marso-Recursion with Macro-B.SPS . * Date: Thu, 12 Dec 2013 00:57:37 -0800 . * From: David Marso <[hidden email]> . * Subject: Re: Recursion with Macro ;-) . * To: [hidden email] . * (Note that there are other postings by the same author, in the . * same thread) . * "The more I reflect the more I am convinced that when the macro . * invokes the recursive call it is the same as if it were calling a . * completely different macro (i.e. all existing internal values are . * preserved until the return). How could it be otherwise?" . * Test of preservation of macro-variable values across calls: . * Example I: A macro calls a different macro: . DEFINE !Outer() ECHO 'Starting macro "<!>Outer":'. !LET !A = 'Alpha' !LET !B = 'Beta' ECHO !QUOTE(!CONCAT('A = ',!A)). ECHO !QUOTE(!CONCAT('B = ',!B)). !Inner ECHO 'Back from the call to "<!>Inner":', ECHO !QUOTE(!CONCAT('Depth = ',!Depth)). ECHO !QUOTE(!CONCAT('A = ',!A)). ECHO !QUOTE(!CONCAT('B = ',!B)). !ENDDEFINE. DEFINE !Inner() !LET !A = 'Gamma' ECHO 'In the macro "<!>Inner":'. ECHO !QUOTE(!CONCAT('A = ',!A)). ECHO !QUOTE(!CONCAT('B = ',!B)). !ENDDEFINE. !Outer. * Example II: A macro calls itself (i.e., a recursive call): . DEFINE !Cursive (Depth=!TOKENS(1)) !IF (!Depth !LT 2) !THEN !LET !A = 'Alpha' !LET !B = 'Beta' ECHO !QUOTE(!CONCAT('Depth = ',!Depth)). ECHO !QUOTE(!CONCAT('A = ',!A)). ECHO !QUOTE(!CONCAT('B = ',!B)). !Cursive Depth = 2 ECHO 'Back from the recursive call:', ECHO !QUOTE(!CONCAT('Depth = ',!Depth)). ECHO !QUOTE(!CONCAT('A = ',!A)). ECHO !QUOTE(!CONCAT('B = ',!B)). !IFEND !IF (!Depth !GE 2) !THEN !LET !A = 'Gamma' ECHO 'In the recursive instance:'. ECHO !QUOTE(!CONCAT('Depth = ',!Depth)). ECHO !QUOTE(!CONCAT('A = ',!A)). ECHO !QUOTE(!CONCAT('B = ',!B)). !IFEND !ENDDEFINE. !Cursive Depth=1. ===================== To manage your subscription to SPSSX-L, send a message to [hidden email] (not to SPSSX-L), with no body text except the command. To leave the list, send the command SIGNOFF SPSSX-L For a list of commands to manage subscriptions, send the command INFO REFCARD |
In reply to this post by David Marso
At 11:51 AM 12/11/2013, David Marso wrote:
As David Marso has demonstrated, SPSS macros can carry out tail-recursion very neatly. (To recapitulate: a program is tail-recursive if it calls itself as its last act before terminating.) Tail recursion is inherently simpler than full recursion; it can always be replaced by a loop. However, as David Marso has worked out, tail-recursion can be a neater way than explicit looping for writing macros to get certain effects: particularly, for acting on all tuples of corresponding elements of a set of lists; and for acting on all pairs of elements of a single list. Both are illustrated below, using ECHO to print the tuples (in the first example) and the pairs (in the second). * I. Step through three lists in parallel. This may be modified . * for more or fewer lists; and the action taken on each triple . * may be anything desired. . * (Code adapted from David Marso.) . DEFINE !Parallel3 ( !POS !CHAREND ("/") / !POS !CHAREND ("/") / !POS !CMDEND ). !LET !Msg = !CONCAT(' ', !HEAD(!1),' ', !HEAD(!2),' ', !HEAD(!3)) . ECHO !QUOTE(!Msg). !IF (!TAIL(!1) !NE !NULL) !THEN !Parallel3 !TAIL(!1) / !TAIL(!2) / !TAIL(!3). !IFEND !ENDDEFINE. !Parallel3 1 2 3 / A B C / Alpha Beta Gamma. 1 A Alpha 2 B Beta 3 C Gamma * II. Generate all pairs of two elements from a list. Again, the . * the action taken on each pair may be anything desired. . * (For clarity, this macro emits a blank line before the output . * from each invocation.) . DEFINE !AllPairs (!POS !CMDEND ). . ECHO ' '. !LET !Left = !HEAD(!1) !DO !Right !IN (!TAIL(!1)) !LET !Msg = !CONCAT(' ',!Left,' ',!Right) . ECHO !QUOTE(!Msg). !DOEND !IF (!TAIL(!TAIL(!1)) !NE !NULL) !THEN !AllPairs !TAIL(!1) . !IFEND !ENDDEFINE. !AllPairs A B C D E. A B A C A D A E B C B D B E C D C E D E !AllPairs A. ================== APPENDIX: All code ================== * C:\Documents and Settings\Richard\My Documents . * \Technical\spssx-l\Z-2013\ . * 2013-12-11 Marso-Recursion with Macro-C.SPS . * In response to posting . * Date: Wed, 11 Dec 2013 08:51:32 -0800 . * From: David Marso <[hidden email]> . * Subject: Re: Recursion with Macro ;-) . * To: [hidden email] . * Note: There are other postings by this author in this thread. And . * this is the third example code I've written for posting in this . * thread. (The other two are named with date 2013-12-12.) . * "Passing an arbitrary macro name as a parameter to a macro which . * recursively parses two lists in parallel and invokes the macro . * with the appropriate set of paired values from the lists ;-)" . * This code has illustrations using tail-recursion to step through . * three lists in parallel (deliberately simplified from David's); . * and to emit all possible pairs from two lists. . * I. Step through three lists in parallel. This may be modified . * for more or fewer lists; and the action taken on each triple . * may be anything desired. . * (Code adapted from David Marso.) . DEFINE !Parallel3 ( !POS !CHAREND ("/") / !POS !CHAREND ("/") / !POS !CMDEND ). !LET !Msg = !CONCAT(' ', !HEAD(!1),' ', !HEAD(!2),' ', !HEAD(!3)) . ECHO !QUOTE(!Msg). !IF (!TAIL(!1) !NE !NULL) !THEN !Parallel3 !TAIL(!1) / !TAIL(!2) / !TAIL(!3). !IFEND !ENDDEFINE. !Parallel3 1 2 3 / A B C / Alpha Beta Gamma. * II. Generate all pairs of two elements from a list. Again, the . * the action taken on each pair may be anything desired. . * (For clarity, this macro emits a blank line before the output . * from each invocation.) . DEFINE !AllPairs (!POS !CMDEND ). . ECHO ' '. !LET !Left = !HEAD(!1) !DO !Right !IN (!TAIL(!1)) !LET !Msg = !CONCAT(' ',!Left,' ',!Right) . ECHO !QUOTE(!Msg). !DOEND !IF (!TAIL(!TAIL(!1)) !NE !NULL) !THEN !AllPairs !TAIL(!1) . !IFEND !ENDDEFINE. !AllPairs A B C D E. !AllPairs A. ===================== To manage your subscription to SPSSX-L, send a message to [hidden email] (not to SPSSX-L), with no body text except the command. To leave the list, send the command SIGNOFF SPSSX-L For a list of commands to manage subscriptions, send the command INFO REFCARD |
Administrator
|
Thanks Richard,
I like these examples. I have taken the !AllPairs to the next logical place and created !AllComb;-) If one wants more than 255 chars then output the result to a file! Can you provide an example of a recursive function which is not tail recursion? There has to be something more than simply the recursive call being the LAST thing in the 'function'. If I were to place an ECHO command after the call to !AllComb would that be enough to make this no longer Tail recursion (not that it matters, I like this 'new' technique and really don't care what technical labels anyone wants to place on it)? DEFINE !AllComb (!POS !CHAREND ("/") /!POS !CMDEND). !LET !R="" !DO !I !IN (!2) !LET !I2=!SUBSTR(!I,!LENGTH(!I),1). !DO !J !IN (!1) !IF (!INDEX(!I,!J) !EQ 0 !AND !J !GT !I2) !THEN !LET !R=!CONCAT(!R,' ',!UNQUOTE(!I),!J) !IFEND !DOEND !DOEND ECHO "-". ECHO !QUOTE(!R). !IF (!TAIL(!1) !NE !NULL) !THEN !AllComb !TAIL(!1) / !R . !IFEND !ENDDEFINE . !AllComb A B C D E F / '' . A B C D E F - AB AC AD AE AF BC BD BE BF CD CE CF DE DF EF - ABC ABD ABE ABF ACD ACE ACF ADE ADF AEF BCD BCE BCF BDE BDF BEF CDE CDF CEF DEF - ABCD ABCE ABCF ABDE ABDF ABEF ACDE ACDF ACEF ADEF BCDE BCDF BCEF BDEF CDEF - ABCDE ABCDF ABCEF ABDEF ACDEF BCDEF - ABCDEF
Please reply to the list and not to my personal email.
Those desiring my consulting or training services please feel free to email me. --- "Nolite dare sanctum canibus neque mittatis margaritas vestras ante porcos ne forte conculcent eas pedibus suis." Cum es damnatorum possederunt porcos iens ut salire off sanguinum cliff in abyssum?" |
At 08:36 AM 12/17/2013, David Marso wrote:
>If I were to place an ECHO command after the call to !AllComb would >that be enough to make this no longer Tail recursion? Yes, in the strict technical sense. But if the ECHO would be just as satisfactory before, or if the ECHO doesn't make use of any internal variables of the caller, it's a trivial instance. >Can you provide an example of a recursive function which is not tail >recursion? OK. You wanted to generate all combinations from a list. Here's a recursive rule for generating all combinations: {All combinations of all elements} = {All combinations containing the first element} UNION {All combinations NOT containing the first element} Here's a macro implementation. In this macro, "!Set" is a list of elements, from which all combinations will be generated; "!Fixed" is a list of elements to be prefixed to all combinations from "!Set". (Notice that the output can be interpreted as a count-down binary counter.) DEFINE !AllCombs(Fixed = !CHAREND('/') /Set = !CMDEND) !IF (!Set !EQ !NULL) !THEN . ECHO !QUOTE(!Fixed). !ELSE !LET !With = !CONCAT(!Fixed,' ',!HEAD(!Set)) !LET !Without = !Fixed !AllCombs Fixed = !With / Set = !TAIL(!Set). !AllCombs Fixed = !Without / Set = !TAIL(!Set). !IFEND !ENDDEFINE. !AllCombs Set=A B C D E. A B C D E A B C D A B C E A B C A B D E A B D A B E A B A C D E A C D A C E A C A D E A D A E A B C D E B C D B C E B C B D E B D B E B C D E C D C E C D E D E ================== APPENDIX: All code ================== * C:\Documents and Settings\Richard\My Documents . * \Technical\spssx-l\Z-2013\ . * 2013-12-17 Marso-Recursion with Macro-D.SPS . * In response to posting . * Date: Tue, 17 Dec 2013 05:36:48 -0800 . * From: David Marso <[hidden email]> . * Subject: Re: Recursion with Macro ;-) . * To: [hidden email] . * ------------------------------------------------------------------ . * Note: There are other postings by this author in this thread. And . * this is the fourth example code I've written for posting in this . * thread -- the other three have earlier dates in their names. . * ------------------------------------------------------------------ . * "Can you provide an example of a recursive function which is not . * tail recursion?" . * OK. You wanted to generate all combinations from a list. Here's a . * recursive rule for generating all combinations: . * . * {All combinations of all elements} = . * {All combinations containing the first element} UNION . * {All combinations NOT containing the first element} . * . * And here's a macro implementation: . * (This includes five lines of inactive trace code, immediately . * following the "DEFINE". Those will be dropped from the posted . * illustration.) . DEFINE !AllCombs(Fixed = !CHAREND('/') /Set = !CMDEND) !LET !MsgF = !CONCAT(' Fixed = ',!Fixed) !LET !MsgS = !CONCAT(' Set = ',!Set) * ECHO 'Entering <!>AllCombs:'. * ECHO !QUOTE(!MsgF). * ECHO !QUOTE(!MsgS). !IF (!Set !EQ !NULL) !THEN . ECHO !QUOTE(!Fixed). !ELSE !LET !With = !CONCAT(!Fixed,' ',!HEAD(!Set)) !LET !Without = !Fixed !AllCombs Fixed = !With / Set = !TAIL(!Set). !AllCombs Fixed = !Without / Set = !TAIL(!Set). !IFEND !ENDDEFINE. !AllCombs Set=A B C D E. ===================== To manage your subscription to SPSSX-L, send a message to [hidden email] (not to SPSSX-L), with no body text except the command. To leave the list, send the command SIGNOFF SPSSX-L For a list of commands to manage subscriptions, send the command INFO REFCARD |
In reply to this post by Richard Ristow
At 03:21 PM 12/11/2013, I wrote:
>I don't think true recursion is possible in SPSS macros, because >they have no local storage. It turns out that this is simply wrong. Macro variables' values *are* local to the macro they are defined in; and to each instance of that macro, if it calls itself. As a result, true recursive macros are possible in SPSS. See earlier postings in this thread, demonstrating both points. ===================== To manage your subscription to SPSSX-L, send a message to [hidden email] (not to SPSSX-L), with no body text except the command. To leave the list, send the command SIGNOFF SPSSX-L For a list of commands to manage subscriptions, send the command INFO REFCARD |
Administrator
|
In reply to this post by Richard Ristow
Thank you Richard for making my head spin with that one ;-) Wonder if there might be an easy way to spit the combos out in an order more of A, B, C, D, A B ,A C, A D, B C, B D, C D, A B C, A B D, A C D, B C D, A B C D Here is a somewhat more mundane example. This one generates nested LOOPS of an arbitrary depth. One could of course do this with a simple !DO with the attendant !HEAD !TAIL parsing of the second 2 lists. But I'm liking this approach MORE and MORE as I twist my brain around the implications. I also tried massaging this into a single macro but couldn't quite resolve the END CASE at the right point. DEFINE !NestLoop (!POS !CHAREND ("/") / !POS !CHAREND ("/") / !POS !CHAREND ("/") / !POS !CMDEND !DEFAULT(1)). !IF (!LENGTH(!2) !GT 0) !THEN LOOP !CONCAT(X,!LENGTH(!1))=!HEAD(!2) TO !HEAD(!3) BY !HEAD(!4). !NestLoop !CONCAT(!1,#)/!TAIL(!2)/!TAIL(!3)/!tail(!4) . !IFEND !ENDDEFINE. DEFINE !UnNest (!POS !CMDEND). !IF (!LENGTH(!1) !GT 0) !THEN END LOOP. !UnNest !TAIL(!1) . !IFEND !ENDDEFINE. DEFINE !Nested (!POS !CHAREND ("/") /!POS !CHAREND ("/") /!POS !CMDEND !DEFAULT(1)). NEW FILE. INPUT PROGRAM. !NestLoop /!1 /!2 /!3. LEAVE ALL. END CASE. !UnNest !1 . END FILE. END INPUT PROGRAM. !ENDDEFINE. SET PRINTBACK ON MPRINT ON. !Nested 1 2 3 4 5 6 7 8 9 9 /1 5 6 8 8 9 10 9 9 10 /1 1 1 2 1 1 2 1 1 1. EXECUTE.
Please reply to the list and not to my personal email.
Those desiring my consulting or training services please feel free to email me. --- "Nolite dare sanctum canibus neque mittatis margaritas vestras ante porcos ne forte conculcent eas pedibus suis." Cum es damnatorum possederunt porcos iens ut salire off sanguinum cliff in abyssum?" |
At 11:26 AM 12/31/2013, David Marso wrote:
>This [macro set] generates nested LOOPS of an arbitrary depth. >I tried massaging this into a single macro but couldn't quite >resolve the END CASE at the right point. Here's a one-macro variation that appears to work. It is, technically, recursive rather than tail-recursive, because it takes an action (emitting "END LOOP") after calling itself. However, this should be considered a trivial case, since the action taken does not depend on the macro's internal state being preserved when it invokes itself. A side issue: your macro set emitted a lot of extraneous periods and blank lines. I've reduced the number of periods emitted by not putting periods after the declaration of the macro arguments, or after the !ENDDEFINE. However, there are still some, and I don't see where they come from. Can you solve that one? DEFINE !NestLoop (!POS !CHAREND ("/") / !POS !CHAREND ("/") / !POS !CHAREND ("/") / !POS !CMDEND !DEFAULT(1)) !IF (!2 !NE !NULL) !THEN !LET !Name = !CONCAT(X,!LENGTH(!1)) . LOOP !Name = !HEAD(!2) TO !HEAD(!3) BY !HEAD(!4). !NestLoop !CONCAT(!1,#)/!TAIL(!2)/!TAIL(!3)/!tail(!4) . . END LOOP. !ELSE. . LEAVE ALL. . END CASE. !IFEND !ENDDEFINE PRESERVE. SET PRINTBACK ON MPRINT ON. NEW FILE. 51 M> NEW FILE. INPUT PROGRAM. 52 M> INPUT PROGRAM. 53 M> !NestLoop /1 2 3 4 5 6 7 8 9 9 /1 5 6 8 8 9 10 9 9 10 /1 1 1 2 1 1 2 1 1 1. 55 M> 56 M> . 57 M> . LOOP X0 = 1 TO 1 BY 1. 58 M> 59 M> . 60 M> . LOOP X1 = 2 TO 5 BY 1. 61 M> 62 M> . 63 M> . LOOP X2 = 3 TO 6 BY 1. 64 M> 65 M> . 66 M> . LOOP X3 = 4 TO 8 BY 2. 67 M> 68 M> . 69 M> . LOOP X4 = 5 TO 8 BY 1. 70 M> 71 M> . 72 M> . LOOP X5 = 6 TO 9 BY 1. 73 M> 74 M> . 75 M> . LOOP X6 = 7 TO 10 BY 2. 76 M> 77 M> . 78 M> . LOOP X7 = 8 TO 9 BY 1. 79 M> 80 M> . 81 M> . LOOP X8 = 9 TO 9 BY 1. 82 M> 83 M> . 84 M> . LOOP X9 = 9 TO 10 BY 1. 85 M> 86 M> . 87 M> 88 M> LEAVE ALL. 89 M> END CASE. 90 M> . 91 M> END LOOP. 92 M> . 93 M> END LOOP. 94 M> . 95 M> END LOOP. 96 M> . 97 M> END LOOP. 98 M> . 99 M> END LOOP. 100 M> . 101 M> END LOOP. 102 M> . 103 M> END LOOP. 104 M> . 105 M> END LOOP. 106 M> . 107 M> END LOOP. 108 M> . 109 M> END LOOP. 110 M> . 111 M> END FILE. 112 M> END FILE. END INPUT PROGRAM. 113 M> END INPUT PROGRAM. 114 M> RESTORE. 115 M> RESTORE. EXECUTE. SHOW N. SHOW |-----------------------------|---------------------------| |Output Created |02-JAN-2014 23:15:37 | |-----------------------------|---------------------------| System Settings |-------|---------------|-------| |Keyword|Description |Setting| |-------|---------------|-------| |N |Number of cases|6144 | | |in the working | | | |data file | | |-------|---------------|-------| ================== APPENDIX: All code ================== * C:\Documents and Settings\Richard\My Documents . * \Technical\spssx-l\Z-2013\ . * 2013-12-31 Marso-Recursion with Macro-E.SPS . * In response to posting . * Date: Tue, 31 Dec 2013 08:26:31 -0800 . * From: David Marso <[hidden email]> . * Subject: Re: Recursion with Macro ;-) . * To: [hidden email] . * "This [macro] generates nested LOOPS of an arbitrary depth. I . * also tried massaging this into a single macro but couldn't quite . * resolve the END CASE at the right point." . * See the original posting for David's code. This attempts a . * single-macro solution, as well as making some changes to match my . * style. . * . * Incidentally, it drops the '.' that David usually uses at the end . * of the DEFINE clause, before the macro body. That period is not . * needed, so it is emitted as part of the macro output. . DEFINE !NestLoop (!POS !CHAREND ("/") / !POS !CHAREND ("/") / !POS !CHAREND ("/") / !POS !CMDEND !DEFAULT(1)) !IF (!2 !NE !NULL) !THEN !LET !Name = !CONCAT(X,!LENGTH(!1)) . LOOP !Name = !HEAD(!2) TO !HEAD(!3) BY !HEAD(!4). !NestLoop !CONCAT(!1,#)/!TAIL(!2)/!TAIL(!3)/!tail(!4) . . END LOOP. !ELSE. . LEAVE ALL. . END CASE. !IFEND !ENDDEFINE PRESERVE. SET PRINTBACK ON MPRINT ON. NEW FILE. INPUT PROGRAM. !NestLoop /1 2 3 4 5 6 7 8 9 9 /1 5 6 8 8 9 10 9 9 10 /1 1 1 2 1 1 2 1 1 1. END FILE. END INPUT PROGRAM. RESTORE. EXECUTE. SHOW N. ===================== To manage your subscription to SPSSX-L, send a message to [hidden email] (not to SPSSX-L), with no body text except the command. To leave the list, send the command SIGNOFF SPSSX-L For a list of commands to manage subscriptions, send the command INFO REFCARD |
Correction. At 11:27 PM 1/2/2014, I wrote:
>Here's a one-macro [solution] It is recursive rather than >tail-recursive, because it takes an action (emitting "END LOOP") >after calling itself. However, this should be considered a trivial >case, since the action taken does not depend on the macro's internal >state being preserved when it invokes itself. It is actually truly, not trivially, recursive, because it *does* depend on state information being retained: namely, how deeply the particular call is nested. That's how it emits the right number of "END LOOP" statements. ===================== To manage your subscription to SPSSX-L, send a message to [hidden email] (not to SPSSX-L), with no body text except the command. To leave the list, send the command SIGNOFF SPSSX-L For a list of commands to manage subscriptions, send the command INFO REFCARD |
Administrator
|
In reply to this post by Richard Ristow
Thanks Richard,
Very nice! "Can you solve that one?" Sure: SET MPRINT OFF PRINTBACK OFF ;-)) Actually have no idea where those are emanating from. Odd that after over 20 years of using Macros I had never thought of trying out these recursion concepts. I'd better not see them popping up in any books without being credited (unlike past history)!!! --
Please reply to the list and not to my personal email.
Those desiring my consulting or training services please feel free to email me. --- "Nolite dare sanctum canibus neque mittatis margaritas vestras ante porcos ne forte conculcent eas pedibus suis." Cum es damnatorum possederunt porcos iens ut salire off sanguinum cliff in abyssum?" |
Free forum by Nabble | Edit this page |