Tipps zur Aufbewahrung in einer Golfsprache


16

Ich schreibe eine Golfsprache.

Schlagen Sie Variablen, Stapel, Bänder, Register usw. zur Speicherung in einer Code-Golf-Sprache vor? Was ist mit impliziten Eingaben?

Grobe Definitionen:

  • Eine Variable ist einfach ein Name (normalerweise ein Zeichen in Golfsprachen), dem ein Wert zugewiesen und später über diesen Namen abgerufen werden kann.
  • Ein Register ist wie eine Variable, verfügt jedoch über eigene (in der Regel Einzelbyte-) Befehle zum Festlegen / Abrufen des Werts.
  • Ein Stapel ist ein Array / eine Liste von Werten variabler Länge, wobei die zuletzt hinzugefügten Werte (die Werte "oben") diejenigen sind, die geändert werden.
  • Eine Warteschlange ist wie ein Stapel, mit der Ausnahme, dass die Werte " unten " geändert werden.
  • Ein Band ist ein statisches Array / eine Liste von Werten, bei denen jeder Wert einen Index hat. Der Hauptunterschied zwischen einem Stapel und einem Band besteht darin, dass die Werte auf einem Band direkt geändert werden.

Ich würde mich freuen, die Vor- und Nachteile jeder Option für verschiedene Szenarien und insgesamt zu kennen. Bitte vermeiden Sie Meinungen und begründete Backup-Aussagen.


1
Ich denke, Sie sollten eine Definition dieser Begriffe in Ihre Frage aufnehmen
Kritixi Lithos

2
@Fatalize Technisch ist die Speichermethode nicht abhängig von der Art der Golfsprache, die Sie machen, die Art der
Golfsprache

1
@ETHproductions Sie sind völlig voneinander abhängig.
Fatalize

1
Ich habe einige grobe Definitionen der verschiedenen Speicherbegriffe hinzugefügt. Sie können sie jederzeit bearbeiten oder zurücksetzen, wenn Sie sie nicht mögen.
ETHproductions

2
Es gibt eine sehr enge Beziehung zwischen der Speichermethode und der Art der Sprache, aber ich denke, Sie müssen sich beide ansehen. Beispielsweise können "imperative" Sprachen (diejenigen, die ihre Anweisungen strikt von links nach rechts ausführen) stapelbasiert (CJam, 05AB1E), bandbasiert (BrainF ***) oder etwas ganz anderes (V, das verwendet) sein ein großer 2D-String, der "Buffer" genannt wird, zusammen mit ein paar Registern). Es gibt auch Präfix-basierte Sprachen (Pyth), Infix-basierte Sprachen (Japt, Pip und im Grunde jede gängige Sprache), Link-basierte Sprachen (Jelly) usw., die alle kaum eine der genannten Methoden anwenden.
ETHproductions

Antworten:


4

Bei allen Speichertypen wird etwas an einem Punkt gespeichert und später abgerufen. Um dies in nur einer Operation zu tun, sollten Sie entweder automatisch speichern oder abrufen und die Position des gespeicherten Werts in der anderen Operation angeben.

Das heißt, Sie können zum expliziten Speichern einen Operator erstellen, um den n-ten berechneten Wert vor dieser Operation abzurufen, oder den aktuellen Wert nach n Operationen zurücksetzen. Alternativ können Sie die absolute Position vom Start des Programms an verwenden oder weitere Aktionen ausführen, z. B. das automatische Entfernen einiger Elemente nach bestimmten Vorgängen (z. B. in einem Stapel). Sie können auch mehrere Operatoren erstellen und mit oder ohne diese automatischen Vorgänge von verschiedenen Kopien des Speichers abrufen. Und Sie sollten versuchen, die maximale Anzahl, die für die Angabe in den Vorgängen erforderlich ist, angemessen klein zu halten, damit Sie für jede Nummer einen Operator zuweisen können.

In den meisten Fällen benötigen Sie jedoch nicht einmal einen Operator und die Sprache erledigt dies implizit. In diesem Fall müssen Sie ein standardisierteres Modell wie Stapel oder Warteschlangen in Betracht ziehen. Das bisher erfolgreichste schien die stillschweigende Programmierung zu sein, bei der nicht einmal die direkte Speicherung erwähnt wird.

Wenn Sie ein neues solches Modell entwerfen möchten, können Sie versuchen, die Auswertungen als Tag zu erweitern und sich einen Standardtag vorzustellen, wenn nichts anderes angegeben ist. Die Standardeinstellung ist höchstwahrscheinlich nur ein Baum, mit der Ausnahme, dass mehrere Blätter mit derselben Eingabe verknüpft sein können. Sie können beispielsweise eine Warteschlange für einen ausgeglichenen Baum oder einen Stapel für einen tiefen Baum verwenden, bei dem die Blätter meist konstant sind, oder Jelly für einen tiefen Baum, bei dem die Blätter meist Kopien der Eingabe sind.

Beachten Sie jedoch, dass Sie die Form eines Binärbaums in nur 2 Bits pro Operator codieren können. Wenn Ihre Sprache also weniger als 64 Operatoren enthält, können Sie die herkömmlichen Modelle ignorieren und einfach den gesamten Baum in die Ersatzbits kodieren (nennen Sie sie "Combine_parent" und "Below_leaf"). Selbst wenn es mehr Operatoren gibt, können Sie einen recht guten Standardwert (wie das Modell von Jelly) und drei Modifikatoren festlegen, um ihn zu ändern.

Sie könnten das gleiche Modell für die implizite und explizite Speicherung verwenden, müssen dies jedoch nicht. Beispielsweise könnten Sie einen Stapel für die implizite Speicherung verwenden, jedoch keine Elemente im expliziten Speicher (oder in einem anderen expliziten Speicher zusätzlich zum impliziten Speicher) einfügen. Es ist wahrscheinlich, dass es in der endgültigen Dokumentation nicht als Stapel bezeichnet wird, aber Sie haben die Idee.

Als Referenz ist die Größe der perfekten Kodierung eines Binärbaums der Logarithmus der katalanischen Zahlen . Und die Größe der perfekten Kodierung eines "binären" Tags ist der Logarithmus von A082161 , aber offensichtlich unpraktisch. Dies setzt voraus, dass ein Operator mit unterschiedlicher Argumentreihenfolge zwei verschiedene Operatoren hat und ein weiteres Bit hinzufügt, wenn dies nicht der Fall ist.

Manchmal möchten Sie vielleicht immer noch Variablen für die Schleifen. Möglicherweise können die Schleifen auf andere Weise neu geschrieben werden. Aber wenn Sie es wirklich brauchen, verwenden Sie kein 1-Byte-Konstrukt zusätzlich zu einem Namen, um die Variable zu definieren. Wenn Sie nicht nur die vorinitialisierten Werte verwenden, ist es normalerweise effizienter, ein 1-Bit-Flag zu verwenden, um anzugeben, ob Sie diese Variable lesen oder schreiben.


7

Ich schlage sie alle vor!

Im Ernst, sie sind alle manchmal nützlich, und je mehr, desto besser! Implizite Eingaben sind niemals schlecht. Sie müssen lediglich ein Flag verwenden, um sie zu deaktivieren. Variablen sind hilfreich, damit sie nicht auf einem Stapel oder Band gefunden werden müssen. Gleiches gilt für Register. Stapel sind hilfreich zum Speichern von Daten, ebenso wie Bänder. Ich empfehle, mehrere zu implementieren, beispielsweise einen Stack und Register, oder einen Stack und Variablen wie GolfScript. Wenn Sie jede Funktion zu einem Byte machen können, wird Ihre Sprache beim Golfen wahrscheinlich effektiv sein, da Sie die Vorteile der einzelnen Funktionen nutzen können.

Ein Beispiel:

  • Angenommen, ich möchte zwei Zahlen als Eingaben verwenden und deren Zeichenfolgenlängen hinzufügen
  • Variablen sind möglicherweise besser dafür (ein Stapel möglicherweise nicht)
  • Beispielcode in GolfScript (mit impliziter Eingabe):

    ~,\,+
    ~ # Eval input (e.g. "1 2" > 1, 2)
    , # Take Length
    \ # Reverse items on the stack
    , # Take Length
    + # Add
      # Implicit output
    

    Mit Variablen (ich weiß, es ist länger, es muss nur nicht die Plätze auf dem Stapel tauschen):

    ~,:a;,:b;ab+
    ~ # Eval input
    , # Get length
    :a# Store in "a"
    ; # Discard value left on stack
    , # Length
    :b# Store in "b"
    ; # Discard
    a # Recall a
    b # Recall b
    + # Add
      # Implicit output
    

Überladungen

Eine andere Sache, die hilfreich sein kann, ist Überlastungen. Wenn Sie beispielsweise eine Funktion zum Speichern von Variablen haben, könnte diese als Monade (Funktion mit einem Eingang; ich bin mir nicht sicher, ob der Begriff außerhalb von J / K / APL verwendet wird) verwendet werden, um sie dem Stapel oder dem Band hinzuzufügen.

Beispiel:

c12 # Stores "1" into register 2
c1] # Pushes "1" onto the stack ("]" is used to denote the end of the monad)

Wenn ein Argument mit den falschen Typen aufgerufen wird, wird es möglicherweise zu einer Warteschlange hinzugefügt, die dann zum Ausfüllen von Werten verwendet wird, wenn der Stapel leer ist.
Esolanging Fruit

5

Ich würde vorschlagen, einen schnell verwendbaren Speicher (von dem gegebenen - Band, Warteschlange, Stapel) und einen permanenten Speicher (Variablen, Register) zu haben, damit die Dinge nicht im Wege stehen, während das Programm etwas anderes tut. Ich würde sagen, viel mehr würde selten etwas geben und mehr Zeichen für mehr 1-Byte-Anweisungen frei lassen.

Nach den gegebenen Definitionen sind die, von denen ich denke, dass sie am besten funktionieren, ein Stapel und Register.
Ein Stapel, weil ein Band Funktionen verwenden muss, um ein neues Objekt darin zu speichern, während ein Stapel einfache Push- und Pop-Funktionen haben sollte (normalerweise in den Befehlen enthalten). Register, weil sie im Vergleich zu Variablen normalerweise weniger Bytes benötigen und wenn Sie mehr als 2-4 verschiedene Dinge für etwas speichern müssen, machen Sie etwas falsch.

Beschränken Sie die Funktionen nicht nur auf das, was ihre Namen oder Definitionen vermuten lassen - einige Funktionen wie put the 1st thing of the stack on top of the stackkönnen definitiv helfen.


5

Grundsätzlich gibt es zwei Arten von Speicher, die unterschiedlich behandelt werden müssen. Zugriff auf kürzlich generierte Werte und / oder die Eingaben; und langfristige Lagerung.

Für die Langzeitspeicherung scheinen Variablen am besten zu funktionieren. Alles mit einer begrenzten Anzahl von Optionen lässt sich nicht skalieren (obwohl Sprachen mit dieser Eigenschaft, wie Jelly, auch bei mittelgroßen Aufgaben ziemlich gut funktionieren). Es ist jedoch meistens nicht erforderlich, Variablennamen anzugeben, wenn die Variable gespeichert wird. Sie müssen lediglich einen Befehl zum Speichern eines Werts in der Variablen ausführen und die Namen nach einem vorhersagbaren Muster automatisch generieren, sodass das Speichern und Abrufen des Werts in einfachen Fällen jeweils ein Befehl sein kann. (Sie könnten beispielsweise Befehle zum Wiederherstellen der zuletzt zugewiesenen Variablen, der zuletzt zweiten, der zuletzt dritten usw. bis zu einer kleinen festen Zahl sowie eines allgemeinen Befehls haben, der ein Argument angenommen hat.)

Für die kurzfristige Speicherung soll so viel wie möglich implizit sein. Fast alle Golfsprachen, die ich gesehen habe, verbinden standardmäßig die Ausgabe eines Befehls mit einer Eingabe des nächsten. Die genaue Art und Weise, in der dies geschieht, ist von Sprache zu Sprache unterschiedlich, kommt aber normalerweise auf dasselbe hinaus. Interessanter ist jedoch die zweite Eingabe für einen Befehl mit zwei Eingängen. Die Entnahme von einem Stapel funktioniert gut, wenn Werte nur einmal verwendet werden, die Skalierung bei der Wiederverwendung von Werten jedoch nicht gut ist. (Versuchen Sie, Stapelmanipulationsprimitive zu vermeiden. Wenn Sie auf deren Verwendung zurückgreifen müssen, verschwenden Sie viele Bytes.) Alternativ können Sie durch die Verwendung von Benutzereingaben oder einer kürzlich zugewiesenen Variablen als implizites zweites Argument einige Byte einsparen einfache Programme, obwohl Sie

In einer Golf-Sprache, an der ich gerade arbeite, verwende ich eine Kombination aus einem sehr günstigen Mechanismus (ein einzelnes Bit ), um die Form des Analysebaums anzugeben, wobei automatisch fehlende Argumente aus Benutzereingaben und ein Checkpointing eingefügt werden Ansatz, der es ermöglicht, den Standard für fehlende Argumente auf etwas anderes festzulegen (plus viele Sonderfälle). Irgendwann werde ich wahrscheinlich Variablen hinzufügen, um Informationen über größere Entfernungen entlang des Programms zu kommunizieren.


0

Ich schlage ein Band und ein Register vor.

Ich bevorzuge Bänder gegenüber Stapeln, da Bänder tendenziell weniger Elemente enthalten, was die Manipulation erleichtert. Die Möglichkeit, Elemente auf dem Band im Register zu platzieren und umgekehrt, sorgt für einen einfachen, kurzen Code.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.