Tipps zum Golfen in Tcl

15

Welche allgemeinen Tipps haben Sie zum Golfen in Tcl? Ich bin auf der Suche nach Ideen, die allgemein auf Code-Golf-Probleme angewendet werden können, die zumindest etwas spezifisch für Tcl sind (z. B. "Kommentare entfernen" ist keine Antwort). Bitte posten Sie einen Tipp pro Antwort.

Johannes Kuhn
quelle

Antworten:

7

Verwenden Sie lmapstattdessen foreach. Dies erfordert Tcl 8.6.

Die Syntax ist dieselbe, gibt jedoch lmapeine Liste mit dem Ergebnis jeder Schleife zurück.

Johannes Kuhn
quelle
4

Auf meine Antwort /codegolf//a/107557/29325 kann ich zeigen:

  1. Ist normalerweise set j 0;while \$j<$n;{...;incr j}kürzer als das Äquivalentfor {set j 0} {$j<$n} {incr j} {...}

  2. Wenn die Schleifenvariable bei 1 beginnt, können wir das Inkrement als Teil der whileTestbedingung durchführen, ohne set i 1unnötigerweise vorher schreiben zu müssen : while {[incr i]<=$n} {...}stattset i 1;while \$i<=$n;{...;incr i}

ACHTUNG : Das kann man nur bei einer äußeren Schleife machen! Ich konnte es nicht auf meine jVariable anwenden, da es außerhalb seiner eigenen inneren Schleife auf 1 zurückgesetzt werden muss! Und incr jwürde den Wert erhalten, der im letzten Schritt der inneren Schleife festgelegt wurde, anstatt eine undefinierte Variable jzu übernehmen 0und zu erhöhen 1!

Sergiol
quelle
4

Manchmal ist es wert zu verwenden , time {script} nwo ndie Anzahl der Iterationen statt einem normalen whileoder forSchleife. Obwohl timeder Zweck nicht das Schleifen ist, ist der erzielte Effekt derselbe.

Ich habe vor kurzem Änderungen an meinen eigenen Antworten vorgenommen, indem ich dieser Anweisung gefolgt bin.

UPDATE: Ich habe gerade eine leicht zu fällende Falle entdeckt: Sie können a foroder a nicht whiledurch einen timeBlock ersetzen , wenn er a breakoder a enthält continue.

Sergiol
quelle
3

Verwenden Sie die interaktive Shell. Auf diese Weise können Sie die Befehlsnamen abkürzen, solange nur 1 Befehl mit den verbleibenden Buchstaben beginnt.

Beispiel:

  • gets -> ge
  • lassign -> las
  • expr -> exp
  • puts -> pu

Und interaktive Lösungen sind kostenlos: P

Hintergrund :

Wenn es tclshmit einem Terminal als Eingabegerät ausgeführt wird, setzt es die Variable tcl_interactiveauf 1. Dies veranlasst unknown(Standardprozedur, die aufgerufen wird, wenn ein Befehl nicht gefunden werden kann), nach Befehlen zu suchen, die mit diesem Namen beginnen.

Nachteil: Es wird das Ergebnis jeder Zeile gedruckt und ;anstelle von Zeilenumbrüchen verwendet.
Ohh, und es könnte externe Befehle wie aufrufen w, was eine gute Abkürzung für ist while.

Johannes Kuhn
quelle
3

Unterbefehle und Optionen können (normalerweise) abgekürzt werden. Dies kann einiges einsparen, aber Sie müssen testen, da nicht alles auf diese Weise gekürzt werden regsubkann (z. B. die Optionen von können nicht).

Sie können dies dann mit der Magie verwenden namespace, einige wirklich böse Dinge zu tun. Bedenken Sie:

namespace exp *;namespace en cr -c ?

Danach ?ist es nun ein magischer Befehl, mit dem Sie jeden globalen Tcl-Befehl abkürzen können, und das alles ohne die böse Unsicherheit, mit dem Sie herumspielen müssen unknown.

Donal Fellows
quelle
2

Ich verwende Tcl 8.0.5, aber ich glaube, dass das Folgende für alle neueren Versionen gilt.

  1. Verwenden Sie renamezum Umbenennen rename:

    rename rename &
    

    Das &kann ein beliebiger Bezeichner sein; &erinnert mich nur an "Referenzen" in C.

  2. Verwenden Sie die umbenannte, renameum umzubenennen set:

    & set =
    

    Auch hier =kann es sich um einen beliebigen Bezeichner handeln. =ist für mich nur intuitiv.

  3. Benennen Sie nun andere Befehle um, die es wert sind, umbenannt zu werden, z

    & regsub R
    & string S
    & while W
    

    Ein Befehl ist es wert, umbenannt zu werden, wenn aufgrund seiner Länge n und Vorkommen k , k (n-1) - (n + 4)> 0 . Wenn man nach k auflöst, erhält man die Formel k > (n+4)/(n-1). Hier ist eine Referenztabelle, die es einfach macht:

    length of       minimum         example(s)
    command         occurrences
    ------------------------------------------------
    2               6               if (consider renaming to "?")
    3               4               for, set (consider renaming to "=")
    4               3               eval, expr, incr (consider renaming to "+"), info, join, proc, puts, scan
    5               3               break, catch, lsort, split, subst, trace, unset, while
    6               3               format, lindex, lrange, regexp, regsub, rename, return, string, switch
    7               2               foreach, lappend, linsert, llength, lsearch, unknown
    .               2               lreplace
    .               2               continue
    .               2               
    
  4. Als nächstes kompaktieren Sie häufig verwendete Unterbefehle wie

    = I index
    = L length
    

    so können Sie Dinge tun wie

    S $I $x 7
    S $L $x
    
  5. Einige offensichtliche Verschiedenes:

    1. lappend kann das erste Element einer Liste setzen, wenn es noch nicht existiert (keine Initialisierung erforderlich).
    2. Sie können Arrays eingestellt , ohne array, zB set doesNotExist(7) 43 .
    3. Sie können "a b c"anstelle von strings ( ) verwenden [list a b c].
    4. Sie können wie so in Strings interpolieren: foo${a}bar.
    5. Sie können two\ wordseher als verwenden "two words". (Denken Sie im Allgemeinen daran, dass bei zusammenhängenden Zeichenfolgen ohne Leerzeichen doppelte Anführungszeichen weggelassen werden können!)
    6. Sie können fors fast immer als whiles umschreiben , um ein oder zwei Zeichen zu speichern, da a whilegleichzeitig prüfen und inkrementieren kann, während a forseparate Blöcke verwendet.
  6. Für größere Programme ist hier ein Trick, den ich mir überlegt habe, aber noch nicht angewendet habe:

    proc unknown {c args} {eval [info commands $c*] $args}
    

    Dies emuliert interaktive Befehlsabkürzungen! Es kostet 54 Zeichen, aber jetzt können Sie jfür join, spfür split, stfür string, wfür whileusw. verwenden.

Andrew Cheong
quelle
1
Wenn Sie interaktive Abkürzungen emulieren möchten, verwenden Sieinfo script {};set tcl_interactive 1
Johannes Kuhn
Cool, danke! Ich habe dich hier gutgeschrieben . Es gab jedoch einige Probleme mit dieser Technik, auf die ich bei der unknownRoute nicht gestoßen bin : siehe hier und hier .
Andrew Cheong
Die Frage fragt nach Tipps, die etwas spezifisch für Tcl sind. Der ternäre Operator ist in den Tipps für alle Sprachen enthalten .
Peter Taylor
@ PeterTaylor - Danke, ich habe diesen Tipp entfernt.
Andrew Cheong
2

sonst ist optional

Wie es auf der Manualpage steht , elseist dies bei ifBlockkonstrukten implizit . Also was ist

if ... {} else {}

kann werden

if ... {} {}

Wie Sie auf einigen meiner Antworten sehen können.

Sergiol
quelle
1

Vielleicht sollte es in eine andere Antwort integriert werden, aber hier ist es:

Wenn a procnur einen Parameter hat, kann es als geschrieben werden

proc p a {DO THINGS}

Anstatt von

proc p {a} {DO THINGS}

Gleiches gilt für zwei Parameter procmit einem Backslash. es kann geschrieben werden als

proc p a\ b {DO THINGS}

Anstatt von

proc p {a b} {DO THINGS}

Für eine höhere Anzahl von Parametern wird der {}Code kürzer gerendert.

Sergiol
quelle
1

Manchmal lohnt es sich, die beiden setAnweisungen zu ersetzen, um Zeichenfolgen durch nur eine lappendAnweisung zu verketten . Bei einer Konstruktion wie dieser kann man ersetzen

set s ""

loop {
    # ...
    set s $s\X
}

durch

loop {
    # ...
    append s X
}

Das append Befehl hat ein incrähnliches Verhalten, das eine noch nicht definierte Variable initialisiert.

Achten Sie darauf, nicht Fehler appenddurchlappend

Sergiol
quelle
1

Wenn Sie eine Liste mit einer Operation bearbeiten, die syntaktisch zwischen den einzelnen Elementen verschachtelt, ist dies manchmal möglich join Elemente für eine bestimmte Operation verwenden, anstatt sie zu durchlaufen.

Unter /codegolf//a/127042/29325 finden Sie ein Beispiel:

puts \n[expr [join [split [read stdin]] +]]

Es read stdingibt 23 214 52dann Split wird die Liste geben {23 214 52}. Nach [join {23 214 52} +]wird die Zeichenfolge zurückgegeben 23+214+52. Endlich expr 23+214+52die Aufgabe des Summierens

Sergiol
quelle
In diesem Fall können Sie das weglassen split.
Johannes Kuhn
@JohannesKuhn: danke. Erledigt.
Sergiol
1

Wenn Sie große Codes haben, ist es möglich , mehrere Nutzungen zu vermeiden , exprindem namespace pat tcl::mathopam Anfang. Es bietet eine Präfix-Syntax-Operation als reguläre Tcl-Funktion. Beispielsweise:

namespace pat tcl::mathop
set sum [+ 1 2 3]
set prod [* {*}{1 2 3 4}]
puts $sum\ $prod

Siehe offizielle Mathop-Dokumentseite

David
quelle
0

Wenn Sie mehrere Variablen in setaufeinanderfolgenden Zeilen haben, können Sie eine lassignanstelle mehrerer setAnweisungen verwenden, um den gleichen Effekt zu erzielen.

Ein Beispiel ist meine eigene Antwort /codegolf//a/105789/29325

Um zu entscheiden, muss man nur die Anzahl der Variablen gewichten (unter der Annahme von 1-Buchstaben-Variablen, wie es beim Golfen zu erwarten ist):

  • <5 setist Golfspieler

  • = 5 setund lassigngeneriere die gleiche Byteanzahl

  • > 5 lassignist Golfspieler

Sergiol
quelle