Rekursiver Generator - manueller Zip gegen Operator

7

Hier ist Übung 5.F.2 aus 'Ein Buch der abstrakten Algebra' von Charles C. Pinter:

  

Lassen Sie G die Gruppe {e, a, b, b^2, b^3, ab, ab^2, ab^3} who sein   Generatoren erfüllen a^2 = e , b^4 = e , ba = ab^3 . Schreibe die Tabelle   von G . ( G wird die Diedergruppe D4 genannt.)

Hier ist ein kleines Perl 6-Programm, das eine Lösung bietet:

%Vor%

So sieht die resultierende Tabelle aus:

Konzentrieren wir uns auf diese speziellen Zeilen von generate :

%Vor%

Für jedes Element in generate wird ein rekursiver Aufruf von @results ausgeführt. Dann führen wir effektiv eine manuelle "Zip" auf die resultierenden Sequenzen. Perl 6 hat jedoch zip und den Operator Z .

Anstelle der obigen Zeilen würde ich gerne so etwas tun:

%Vor%

Also hier ist die vollständige generate mit Z :

%Vor%

Das Problem mit der Z Version von generate ist, dass es hängt ...

Also, meine Frage ist, gibt es eine Möglichkeit, generate in Z zu schreiben?

Neben dieser Kernfrage können Sie alternative Lösungen für die Übung, die Perl 6 erforschen und präsentieren, teilen.

Als ein anderes Beispiel, hier ist Übung 5.F.3 aus dem gleichen Buch:

  

Sei G die Gruppe {e, a, b, b^2, b^3, ab, ab^2, ab^3} who   Generatoren erfüllen a^4 = e , a^2 = b^2 , ba = ab^3 . Schreiben Sie die   Tabelle von G . (G heißt die Quaternion-Gruppe.)

Und das obige Programm zeigt die Tabelle an:

Nebenbei wurde dieses Programm von einer Version in C # konvertiert. So sieht generate dort mit LINQ und einer Version von ZipMany mit freundlicher Genehmigung von

%Vor%

Das gesamte C # -Programm: Link .

    
dharmatech 29.06.2017, 09:59
quelle

4 Antworten

7

Warum Ihre Verwendung von zip nicht funktioniert

Ihr Code geht davon aus, dass [Z] ("mit dem Zip-Operator verkleinern") verwendet werden kann, um die Umsetzung zu erhalten einer Liste von Listen.

Leider funktioniert im allgemeinen Fall nicht. Es 'normalerweise' funktioniert, aber bricht an einem Rand Fall: Nämlich, wenn die Liste der Listen ist eine Liste von genau eine Liste. Beobachte:

%Vor%

In den ersten beiden Beispielen (3 und 2 Unterlisten) können Sie sehen, dass die Transponierung von @a einwandfrei zurückgegeben wurde. Das vierte Beispiel (0 Unterlisten) macht auch das Richtige.
Aber das dritte Beispiel (1 Unterliste) hat a b c nicht wie erwartet gedruckt, dh es wurde in diesem Fall nicht die Transponierung von @a zurückgegeben, sondern (scheinbar) die Transponierung von @a[0] .

Leider ist dies kein Rakudo-Bug (in diesem Fall könnte es einfach behoben werden), sondern eine unvorhergesehene Interaktion zweier Perl 6-Design-Entscheidungen, nämlich:

  • Der reduce-Meta-Operator [ ] behandelt eine Eingabeliste mit einem einzelnen Element, indem er den Operator aufruft, auf den er angewendet wird, mit einem Argument (besagtem Element).
    Falls Sie sich fragen, kann ein Infix-Operator mit nur einem Argument aufgerufen werden, indem das Funktionsobjekt aufgerufen wird: &infix:<Z>( <a b c>, ) .
  • Der zip-Operator Z und die Funktion zip folgen (wie andere eingebaute Listen, die verschachtelte Listen akzeptieren) der sogenannten "Einargument-Regel" - dh ihre Signatur verwendet a Slurpy-Parameter mit einem Argument . Dies bedeutet, dass, wenn es mit einem einzelnen Argument aufgerufen wird, es in es absteigt und seine -Elemente die tatsächlich zu verwendenden Argumente berücksichtigt. (Siehe auch Slurpy-Konventionen .)
    So wird zip(<a b c>,) als zip("a", "b", "c") behandelt.

Beide Funktionen bieten in vielen anderen Fällen einige nützliche Funktionen, aber in diesem Fall stellt ihre Interaktion leider eine Falle dar.

So funktioniert es mit zip

Sie können die Anzahl der Elemente von @arrs und Sonderfall "genau 1 Unterliste" überprüfen:

%Vor%

Das [] ist ein " zen slice " - es gibt die Liste unverändert zurück, aber ohne Der Elementcontainer, in den das übergeordnete Array ihn eingepackt hat. Dies ist erforderlich, da die for -Schleife alles, was in einen Elementcontainer eingeschlossen ist, als einzelnes Element betrachtet und nur eine Iteration ausführt.

Natürlich ist diese if-else-Lösung nicht sehr elegant, was wahrscheinlich den Grund für den Versuch, zip zu verwenden, negiert.

So schreiben Sie den Code eleganter ohne zip

Siehe Christophs Antwort .

    
smls 29.06.2017, 17:52
quelle
6

Das könnte mit Z möglich sein, aber für mein armes kleines Gehirn ist das Zappen rekursiv generierter fauler Listen zu viel.

Stattdessen habe ich einige andere Vereinfachungen gemacht:

%Vor%

Hier ist eine kompakte Neuschreibung von generate , die bidirektionale Substitution durchführt, immer noch ohne eine explizite zip:

%Vor%     
Christoph 29.06.2017 15:40
quelle
5

Hier ist eine Version von generate , die den von smls gezeigten Ansatz verwendet:

%Vor%

Ich habe es getestet und es funktioniert auf die Übungen 2 und 3.

Wie smls in seiner Antwort erwähnt, macht zip nicht das, was wir erwartet haben, als das angegebene Array von Arrays enthalten nur ein einzelnes Array. Also, machen wir eine Version von zip , die funktioniert mit einem oder mehreren Arrays:

%Vor%

Und jetzt generate in zip-many :

%Vor%

Das sieht ziemlich gut aus.

Danke smls !

smls schlägt in einem Kommentar unten Folgendes vor: zip-many nicht aufrufen take , wobei generate beibehalten wird. Lassen Sie uns auch flat von zip-many nach generate verschieben.

Das abgespeckte zip-many :

%Vor%

Und die generate dazu:

%Vor%     
dharmatech 29.06.2017 18:21
quelle
0

Das separate Testen der Schlüssel und Werte scheint etwas albern zu sein; Deine Strings sind keine echten Regexes, also brauchst du // nirgendwo in deinem Code.

%Vor%

Offensichtlich müssen Sie mit dieser Version von generate table neu schreiben, um @eqs anstelle von %eqs zu verwenden.

    
BenGoldberg 06.08.2017 18:18
quelle

Tags und Links