Combinations of things (small puzzler)
[1/9] 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" ;
[2/9] from: lmecir:mbox:vol:cz at: 21-Oct-2001 0:55
Hi Joel,
the cause of REPEAT is exactly the same as the case of USE or MAKE OBJECT!.
I described this behaviour in the Ref-Words application you can launch from
the DOCS folder in the View Desktop.
Cheers
Ladislav
[3/9] from: g:santilli:tiscalinet:it at: 21-Oct-2001 12:18
Hello Joel!
On 20-Ott-01, you wrote:
JN> Sooooooo... Have I missed something in the documentation
JN> somewhere? Note that the right number of lines get printed in
JN> all cases, it's just that the contents are goofy for
JN> recursive invocations of REPEAT with a numeric second
JN> argument.
It looks like REPEAT does something like:
repeat: func ['word value body] [
either series? value [
...
... bind/copy body word ...
...
] [
...
... bind body word ...
...
]
]
(I think you get the idea...) Indeed,
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 copy [
poke b p i
.any-n-dices p + 1 n b
]
]
] 1 n temp
]
produces:
>> some-things: ["camel" "lemur" "mouse"]
== ["camel" "lemur" "mouse"]
>> 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
Sounds like something to report to feedback!
Regards,
Gabriele.
--
Gabriele Santilli <[giesse--writeme--com]> - Amigan - REBOL programmer
Amiga Group Italia sez. L'Aquila -- http://www.amyresource.it/AGI/
[4/9] from: rotenca:telvia:it at: 21-Oct-2001 23:47
Ciao Gabriele,
I am not sure you are right, when you say:
> It looks like REPEAT does something like:
> repeat: func ['word value body] [
<<quoted lines omitted: 6>>
> ... bind body word ...
> ...
It seemes to me that repeat never make a copy of body:
>> x: copy [probe i]
== [probe i]
>> repeat i [1 2 3] x
1
2
3
== 3
>> print get second x
3
>> x: copy [probe i]
== [probe i]
>> repeat i 3 x
1
2
3
== 3
>> print get second x
4
---
Ciao
Romano
[5/9] from: joel:neely:fedex at: 22-Oct-2001 9:48
Hi, Ladislav,
Ladislav Mecir wrote:
> the cause of REPEAT is exactly the same as the case of USE or
> MAKE OBJECT!. I described this behaviour in the Ref-Words
> application you can launch from the DOCS folder in the View
> Desktop.
>
Sorry for the delay in responding... I was View-less for a while
(running on a box that only had Core, and didn't want to overlay
that with View).
The issue I was asking about was not the fact that REPEAT has an
effect on its third argument, but that its behavior is different
depending on the type of the second argument.
-jn-
--
This sentence contradicts itself -- no actually it doesn't.
-- Doug Hofstadter
joel<dot>neely<at>fedex<dot>com
[6/9] from: rotenca:telvia:it at: 22-Oct-2001 20:12
Ciao Gabriele
> It looks like REPEAT does something like:
> repeat: func ['word value body] [
<<quoted lines omitted: 8>>
> ]
> ]
I have checked the version of anyn with series instead of number, and also
that version requires a copy. The problem only seems not to exists but it is
the same...
---
Ciao
Romano
[7/9] from: lmecir:mbox:vol:cz at: 22-Oct-2001 22:13
Aha,
...skip...
> The issue I was asking about was not the fact that REPEAT has an
> effect on its third argument, but that its behavior is different
<<quoted lines omitted: 4>>
> -- Doug Hofstadter
> joel<dot>neely<at>fedex<dot>com
That is not correct, the behaviour of REPEAT is exactly the same - REPEAT
modifies its second argument. The difference in your code was, that 'item in
the case of (repeat item [1 2 3] [...]) did not have the same
responsibility
as 'i in the case of (repeat i 3 [...]). Here is a code
that can show some similarity:
recursive: func [x] [
repeat i x [
if x = 1 [
print ["X:" x "I before recursive call: " i]
recursive 2
print ["X:" x "I after recursive call: " i]
]
]
]
recursive 1
>> recursive 1
X: 1 I before recursive call: 1
X: 1 I after recursive call: 3
blk-recursive: func [x] [
repeat i x [
if (length? x) = 1 [
print ["X:" mold x "I before recursive call: " i]
blk-recursive [1 2]
print ["X:" mold x "I after recursive call: " i]
]
]
]
blk-recursive [1]
>> blk-recursive [1]
X: [1] I before recursive call: 1
X: [1] I after recursive call: 2
Cheers
Ladislav
[8/9] from: lmecir:mbox:vol:cz at: 22-Oct-2001 22:29
Hi myself,
..
> That is not correct, the behaviour of REPEAT is exactly the same - REPEAT
> modifies its second argument
cannot count to three properly, I wanted to say, that REPEAT modified the
BODY argument, sorry.
[9/9] from: g:santilli:tiscalinet:it at: 22-Oct-2001 19:47
Hello Romano!
On 21-Ott-01, you wrote:
RT> It seemes to me that repeat never make a copy of body:
I didn't test it actually, I just based my observation on what
reported by Joel...
Regards,
Gabriele.
--
Gabriele Santilli <[giesse--writeme--com]> - Amigan - REBOL programmer
Amiga Group Italia sez. L'Aquila -- http://www.amyresource.it/AGI/
Notes
- Quoted lines have been omitted from some messages.
View the message alone to see the lines that have been omitted