Mailing List Archive: 49091 messages
  • Home
  • Script library
  • AltME Archive
  • Mailing list
  • Articles Index
  • Site search
 

[REBOL] Combinations of things (small puzzler)

From: joel:neely:fedex at: 20-Oct-2001 16:06

I'm a bit puzzled about the difference in behavior between REPEAT var blockexpression and REPEAT var numericexpression as illustrated by the following little story. It's not clear to me whether this is an inconsistency or a bug. I have a small collection of some things: some-things: ["camel" "lemur" "mouse"] I'd like to print all possible combinations of three of these things (allowing replacement between selections). any3: function [ things [block!] ][ temp ][ temp: array 3 repeat item things [ temp/1: item repeat item things [ temp/2: item repeat item things [ temp/3: item print temp ] ] ] ] which behaves as expected:
>> any3 some-things
camel camel camel camel camel lemur camel camel mouse camel lemur camel camel lemur lemur camel lemur mouse camel mouse camel camel mouse lemur camel mouse mouse lemur camel camel lemur camel lemur lemur camel mouse lemur lemur camel lemur lemur lemur lemur lemur mouse lemur mouse camel lemur mouse lemur lemur mouse mouse mouse camel camel mouse camel lemur mouse camel mouse mouse lemur camel mouse lemur lemur mouse lemur mouse mouse mouse camel mouse mouse lemur mouse mouse mouse
>>
Of course, that function is specialized to picking exactly 3 at a time, which I can overcome with a little recursion. anyn: function [ n [integer!] things [block!] ][ temp ][ temp: array n do .anyn: func [ i [integer!] n [integer!] b [block!] ][ either i > n [ print b ][ repeat item things [ poke b i item .anyn i + 1 n b ] ] ] 1 n temp ] which allows me to say
>> anyn 3 some-things
camel camel camel camel camel lemur camel camel mouse ... and so forth, until ... mouse mouse camel mouse mouse lemur mouse mouse mouse
>>
Now, REPEAT is supposed to be able to step through either the values in a block (for a block argument) or the integers 1 through some limit (for an integer argument). Let's rework ANY3 to use an "indexing" strategy. any-3: function [ things [block!] ][ temp len ][ temp: array 3 len: length? things repeat i len [ temp/1: things/:i repeat i len [ temp/2: things/:i repeat i len [ temp/3: things/:i print temp ] ] ] ] Now, please notice that -- up to this point -- it hasn't mattered that each use of REPEAT in a single solution operates on the same word. But when we try to generalize ANY-3 to make a variable number of selections from our list of some things ... any-n: function [ n [integer!] things [block!] ][ temp len .any-n ][ temp: array n len: length? things do .any-n: func [ p [integer!] n [integer!] b [block!] ][ either p > n [ print b ][ repeat i len [ poke b p things/:i .any-n p + 1 n b ] ] ] 1 n temp ] ... we get a surprise!
>> any-n 3 some-things
camel camel camel camel camel lemur camel camel mouse camel none camel camel none lemur camel none mouse camel none camel camel none lemur camel none mouse none camel camel none camel lemur none camel mouse none none camel none none lemur none none mouse none none camel none none lemur none none mouse none camel camel none camel lemur none camel mouse none none camel none none lemur none none mouse none none camel none none lemur none none mouse
>>
If we get those pesky things out of the way, and just look at the indices ... any-n-dices: function [ n [integer!] things [block!] ][ temp len .any-n ][ temp: array n len: length? things do .any-n-dices: func [ p [integer!] n [integer!] b [block!] ][ either p > n [ print b ][ repeat i len [ poke b p i .any-n-dices p + 1 n b ] ] ] 1 n temp ] ... we see this...
>> any-n-dices 3 some-things
1 1 1 1 1 2 1 1 3 1 4 1 1 4 2 1 4 3 1 4 1 1 4 2 1 4 3 4 1 1 4 1 2 4 1 3 4 4 1 4 4 2 4 4 3 4 4 1 4 4 2 4 4 3 4 1 1 4 1 2 4 1 3 4 4 1 4 4 2 4 4 3 4 4 1 4 4 2 4 4 3
>>
... which shows that there appears to be an interaction between the values of the controlled word at different levels of recursive evaluation, which didn't appear to happen when REPEAT was given a block of values. The obvious work-around is to use an explicit FOR loop (or WHILE) ... for-any-n-dices: function [ n [integer!] things [block!] ][ temp len .for-any-n ][ temp: array n len: length? things do .for-any-n-dices: func [ p [integer!] n [integer!] b [block!] ][ either p > n [ print b ][ for i 1 len 1 [ poke b p i .for-any-n-dices p + 1 n b ] ] ] 1 n temp ] ... which behaves as expected ...
>> for-any-n-dices 3 some-things
1 1 1 1 1 2 1 1 3 1 2 1 1 2 2 1 2 3 1 3 1 1 3 2 1 3 3 2 1 1 2 1 2 2 1 3 2 2 1 2 2 2 2 2 3 2 3 1 2 3 2 2 3 3 3 1 1 3 1 2 3 1 3 3 2 1 3 2 2 3 2 3 3 3 1 3 3 2 3 3 3
>>
... but this certainly violates the expectation that ... REPEAT var number ... and ... FOR var 1 number 1 ... are equivalent REBOL phrases. Sooooooo... Have I missed something in the documentation somewhere? Note that the right number of lines get printed in all cases, it's just that the contents are goofy for recursive invocations of REPEAT with a numeric second argument. -jn- -- ; sub REBOL {}; sub head ($) {@_[0]} REBOL [] # despam: func [e] [replace replace/all e ":" "." "#" "@"] ; sub despam {my ($e) = @_; $e =~ tr/:#/.@/; return "\n$e"} print head reverse despam "moc:xedef#yleen:leoj" ;