Here's exercise 5.F.2 from 'A Book of Abstract Algebra' by Charles C Pinter:
Let
G
be the group{e, a, b, b^2, b^3, ab, ab^2, ab^3}
whose generators satisfya^2 = e
,b^4 = e
,ba = ab^3
. Write the table ofG
. (G
is called the dihedral group D4.)
Here's a little Perl 6 program which presents a solution:
sub generate(%eqs, $s)
{
my @results = ();
for %eqs.kv -> $key, $val {
if $s ~~ /$key/ { @results.push($s.subst(/$key/, $val)); }
if $s ~~ /$val/ { @results.push($s.subst(/$val/, $key)); }
}
for @results -> $result { take $result; }
my @arrs = @results.map({ gather generate(%eqs, $_) });
my $i = 0;
while (1)
{
for @arrs -> @arr { take @arr[$i]; }
$i++;
}
}
sub table(@G, %eqs)
{
printf " |"; for @G -> $y { printf "%-5s|", $y; }; say '';
printf "-----|"; for @G -> $y { printf "-----|"; }; say '';
for @G -> $x {
printf "%-5s|", $x;
for @G -> $y {
my $result = (gather generate(%eqs, "$x$y")).first(* (elem) @G);
printf "%-5s|", $result;
}
say ''
}
}
# ----------------------------------------------------------------------
# Pinter 5.F.2
my @G = <e a b bb bbb ab abb abbb>;
my %eqs = <aa e bbbb e ba abbb>; %eqs<e> = '';
table @G, %eqs;
Here's what the resulting table looks like:
Let's focus on these particular lines from generate
:
my @arrs = @results.map({ gather generate(%eqs, $_) });
my $i = 0;
while (1)
{
for @arrs -> @arr { take @arr[$i]; }
$i++;
}
A recursive call to generate
is made for each of the items in @results
. Then we're effectively performing a manual 'zip' on the resulting sequences. However, Perl 6 has zip
and the Z
operator.
Instead of the above lines, I'd like to do something like this:
for ([Z] @results.map({ gather generate(%eqs, $_) })).flat -> $elt { take $elt; }
So here's the full generate
using Z
:
sub generate(%eqs, $s)
{
my @results = ();
for %eqs.kv -> $key, $val {
if $s ~~ /$key/ { @results.push($s.subst(/$key/, $val)); }
if $s ~~ /$val/ { @results.push($s.subst(/$val/, $key)); }
}
for @results -> $result { take $result; }
for ([Z] @results.map({ gather generate(%eqs, $_) })).flat -> $elt { take $elt; }
}
The issue with the Z
version of generate is that it hangs...
So, my question is, is there a way to write generate
in terms of Z
?
Besides this core question, feel free to share alternative solutions to the exercise which explore and showcase Perl 6.
As another example, here's exercise 5.F.3 from the same book:
Let G be the group
{e, a, b, b^2, b^3, ab, ab^2, ab^3}
whose generators satisfya^4 = e
,a^2 = b^2
,ba = ab^3
. Write the table ofG
. (G is called the quaternion group.)
And the program above displaying the table:
As an aside, this program was converted from a version in C#. Here's how generate
looks there using LINQ and a version of ZipMany courtesy of Eric Lippert.
static IEnumerable<string> generate(Dictionary<string,string> eqs, string s)
{
var results = new List<string>();
foreach (var elt in eqs)
{
if (new Regex(elt.Key).IsMatch(s))
results.Add(new Regex(elt.Key).Replace(s, elt.Value, 1));
if (new Regex(elt.Value).IsMatch(s))
results.Add(new Regex(elt.Value).Replace(s, elt.Key, 1));
}
foreach (var result in results) yield return result;
foreach (var elt in ZipMany(results.Select(elt => generate(eqs, elt)), elts => elts).SelectMany(elts => elts))
yield return elt;
}
The entire C# program: link.