> >     use Permutations <<permutations compositions>>;
> > 
> >     # Generate all strings of length $n
> >     method Rule::Group::generate(Int $n) {  # Type sprinkles :)
> >         compositions($n, [EMAIL PROTECTED]) ==> map {
> >             my @rets = map { 
> >                 $^atom.generate($^n)
> >             } zip(@.atoms, $_);
> >             *permutations([EMAIL PROTECTED])
> >         }
> >     }

Oops, I didn't do it right.  That last line should be:

    *(map { join '', $_ } permutations([EMAIL PROTECTED])) 

instead of the plain *permutations([EMAIL PROTECTED]).

At first I thought there was a problem if a subpattern returned the
null list, indicating a non-match.  But then, if permutations is
strictly mathematical, it will return the null list if any of its
arguments are the null list anyway.

Plus the joining bit, so we get strings back instead of arrays.

> Pardon my ignorance, here:   
> 
> For the example:  /(A*B*(C*|Z+))/.generate(4)
> 
> >         compositions($n, [EMAIL PROTECTED]) ==> map {
> 
> This C< [EMAIL PROTECTED] > is supposed to compute the length of the @.atoms
> member-array, right? So that you can call "compositions($a,$b)" with
> two numbers?

That was my intent.  If compositions imposes numeric context, the +
isn't necessary, but I think it's good for clarity anyway.

> compositions(4,3) = [
>   [0, 0, 4],
>   [0, 1, 3],
>   [0, 2, 2],
>    :
>   [4, 0, 0]
> ]
> 
> right?

Yep.

> And then map passes each of the 3-tuples, above, to the block as $_.
> 
> >             my @rets = map { 
> >                 $^atom.generate($^n)
> >             } zip(@.atoms, $_);
> >             *permutations([EMAIL PROTECTED])

Yes.  (I suppose I should have parameterized it with -> $composition,
or somesuch (or better yet, -> @composition)).

> And the block is going to take the @.atoms array, which has (in my
> example) three members: A*, B*, and (C*|Z+); and the 3-tuple, and pair
> each @.atom with a number from the 3-tuple in $_ via the zip function.
> 
> A* => 1, B* => 2, (C*|Z+) => 1,

Yes.  (I loathe the name "zip", FWIW.  "dead_cat" would have been more
descriptive... :)

> And map will run A*.generate(1), B*.generate(2), (C*|Z+).generate(1)
> because the ^atom and ^n are alphabetically the first and second
> arguments. (Note: I had thought that currying was limited to one-char
> names, but I can't find anything right now about it...I like multichar
> names better [as in this example], but it's going to take a lot of
> practice to learn to watch out for that '^'.)
> 
> And then presumably the results would be:
> 
> A* => [ 'A' ]              # Array of one, for compatibility (below)
> B* => [ 'BB' ]             # ditto
> (C*|Z+) => [ 'C', 'Z' ]

[...]

> Continuing:
> 
> my @rets = [ ['A'], ['BB'], ['C', 'Z'] ]
> 
> When you say 
> 
> >             *permutations([EMAIL PROTECTED])
> 
> The [EMAIL PROTECTED] is supposed to flatten the array once, right? So that the
> effect was as if you had stripped off the outer [ ... ] above.
> 
> And permutations presumably iterates over each possible setting for
> each independent argument.

That was my intention.  I don't think this is strictly a
"permutations" operation, but I couldn't think of what it was.

> sub permutations([EMAIL PROTECTED], [EMAIL PROTECTED])
> {
>   @arg1 ==> map -> $arg {
>      map { $arg, *$_ } permutations(@rest);
>   };     # <-- Is the semicolon needed?
> }

Semicolon isn't needed.  It's a separator, not a terminator.

That is a rockin' definition of C<permutations>. :)

> Which should generate
> [   ['A', 'BB', 'C', ]   ,    ['A', 'BB', 'Z', ]  ]
> 
> and then strip off the [ , ] because of the * in *permutations,
> yielding the list.
> 
> The final strippage is because the *permutations() is making up only a
> single component of the product of the map output, right? In order to
> get
> 
> [ ['CCCC'], ..., [ 'A', 'BB', 'C', ], ['A', 'BB', 'Z'], ... ]
> 
> you flatten once to "glue" them together?

Umm, the new code does it better.

[...]
 
> =Austin

Reply via email to