Golftipps in Husk

15

Husk ist eine völlig neue Golfsprache, die von den PPCG-Nutzern Leo und Zgarb entwickelt wurde . Es hat begonnen, immer wettbewerbsfähiger zu werden, oft in der Nähe zu bleiben oder sogar Sprachen zu schlagen, die bekanntermaßen sehr knapp sind, wie Jelly und 05AB1E.

Lassen Sie uns einige Golftechniken auflisten, die etwas spezifisch für Husk sind. Bitte poste wie immer einen Tipp pro Antwort.

Mr. Xcoder
quelle
1
@ Totallyhuman erste Husk Antwort Immer noch nicht so neu
H.PWiz

Antworten:

10

Verwenden Sie den Rückgabewert von Prädikaten

In Husk liefern Funktionen, die ihre Eingaben auf eine Eigenschaft prüfen, in der Regel ein aussagekräftiges Ergebnis, da jede positive ganze Zahl wahr ist.

Beispiele:

≠  Numbers: Absolute difference
   Chars:   Absolute difference of code points
   Lists:   First Index where the differ

Comparisons <, >, ≤, ≥:

For strict comparisons:
Numbers,Chars:  max 0 (the appropriate difference¹)
Lists: The first index where the comparison between the two lists is true

For non-strict comparisons:
Numbers,Chars: max 0 (the appropriate difference + 1)
Lists: Either the result of the strict comparison or, if they are equal,
       the length of the list + 1

ṗ  Index into the list of prime numbers

V  The index of the first element for which the condition is true

€  The first index of that element/substring in the list

£  Works like €

&  Given two arguments of the same type will return the second argument if false,
   otherwise will return the first argument

|  Given two arguments of the same type will return the second argument if true,
   otherwise will return the first argument

¦  Return the quotient if divisibility holds

Λ,E,Ë  Will all return length+1 in truthy cases

Char predicates:
□,±,√,D,½  will each return the codepoint of its argument on truthy cases

¹ Geeigneter Unterschied bedeutet Unterschied der Codepunkte für Zeichen. Es bezieht sich auch auf die Argumentreihenfolge. dh für <x y, wärex-y

H.PWiz
quelle
7

Verwenden Sie überlaufende Linienbeschriftungen

Wie Sie vielleicht bereits wissen, [₀-₉]+|[₀-₉]ist es regulär, dass die Syntax eine andere Zeile aufruft als die, in der Sie sich gerade befinden.

Dieser Tipp ist besonders nützlich, wenn Sie möchten, dass eine in einer bestimmten Zeile definierte Funktion als Argument für mehr als eine der Funktionen in der folgenden Tabelle oder als Argument für eine oder mehrere der folgenden Funktionen und für sich selbst aufgerufen wird.

Funktionstabelle:

+----------+----------+
|Index     |Function  |
+----------+----------+
|1         |´ (argdup)|
+----------+----------+
|2         |` (flip)  |
+----------+----------+
|3         |m (map)   |
+----------+----------+
|4         |z (zip)   |
+----------+----------+
|5         |S (hook)  |
+----------+----------+

Zeilen in Ihrem Code sind von oben nach unten mit ihren jeweiligen 0-basierten Indizes gekennzeichnet. Wenn M <N ist , wobei M die Bezeichnung und N die Anzahl der Zeilen in Ihrem Code ist, stellt die Bezeichnung nur die in Zeile M definierte Funktion dar . Wenn N ≤ M <N * 6 ist , repräsentiert es die Funktion aus der obigen Tabelle bei Index ⌊M ÷ N÷, wobei die Funktion in Zeile M mod N als erstes Argument definiert ist. Wenn N * 6 ≤ M ist , wird ein Indexfehler ausgelöst.

Erik der Outgolfer
quelle
5

Lambdas können kürzer sein als neue Funktionen

Wie Sie wahrscheinlich wissen, wenn Sie ein mehrzeiliges Programm haben, können Sie sich auf die Zeilen mit den Indizes beziehen ₀…₉, zum Beispiel im Fall von

f
g

wird sich auf die Funktion beziehen g. Wenn Sie nun immer die Eingaben auf die Funktion anwenden g(und sie mehrmals verwenden); etwas wie das:

f₁⁰[...]g₁⁰[...]
h

Sie sollten ein Lambda einführen, da Sie dadurch 1 Byte für jede weitere Verwendung sparen:

λf⁰[...]g⁰[...])h

Das Gegenteil könnte auch der Fall sein

Im Fall von selbstreferenzierenden Lambdas ( φχψ) gibt es den Sonderfall, dass Sie die Eingaben direkt auf die rekursive Funktion anwenden. In diesen Fällen ist es besser, den Index zu verwenden, anstatt ein neues Lambda zu definieren und zu verwenden .

ბიმო
quelle
5

Verwendungen von Γ

Die Hauptanwendung der integrierten Funktion Γ, die als Mustererkennung in Listen oder Listendekonstruktion bezeichnet wird , besteht darin, eine Liste in einen Kopf und einen Schwanz aufzuteilen und auf diese eine Binärfunktion anzuwenden. Dies entspricht der Haskell-Pattern-Matching-Sprache

f (x : xs) = <something>
f [] = <something else>

wo <something>ein Ausdruck enthält x, xsund gegebenenfalls f. Es gibt 4 Überladungen von Γ, von denen jede ein wenig anders funktioniert.

list

Die erste Überladung listnimmt einen Wert aund eine Binärfunktion an f. Es gibt eine neue Funktion zurück, die eine Liste aufnimmt, zurückgibt, awenn sie leer ist, und fKopf und Schwanz aufruft, wenn sie nicht leer ist. Nimmt zum Beispiel Γ_1€eine Liste, gibt -1sie zurück, wenn sie leer ist, und den Index des ersten Vorkommens des ersten Elements im Ende, wenn nicht.

listN

Die zweite Überladung listNähnelt list, außer dass sie aweggelassen wird und stattdessen der Standardwert des Rückgabetyps verwendet wird. Zum Beispiel Γ€ist äquivalent zu Γ0€, da der numerische Standardwert ist 0.

In der Praxis listNwird häufiger als verwendet list, da der Standardwert entweder irrelevant oder genau das ist, was Sie benötigen. Ein übliches Muster ist Γ~αβγ, wo αβγdrei Funktionen sind; Dies gilt βfür das erste Element und γden Schwanz und kombiniert die Ergebnisse mit α. Es wurde zB in dieser Antwort verwendet . Andere Muster umfassen das Γo:αAnwenden αnur auf das erste Element und das Γ·:mαAnwenden αauf alle Elemente mit Ausnahme des ersten. Letzteres wurde in dieser Antwort verwendet .

listF

Die dritte Überladung ist etwas aufwändiger. Wie listes nimmt einen Wert aund eine Funktion fund gibt eine neue Funktion , gdie eine Liste nimmt. Dieses Mal fwird jedoch ein zusätzliches Funktionsargument benötigt, das gselbst angegeben ist und für jeden Wert aufgerufen werden kann (einschließlich, aber nicht beschränkt auf den Endpunkt der Eingabeliste). Dies bedeutet, dass listFein allgemeines Rekursionsschema für Listen implementiert wird . listFwird nicht sehr oft verwendet, da die explizite Rekursion mit list/ listNnormalerweise genauso lang oder kürzer ist wie in dieser Antwort .

listNF

listNFis to listFwhat listNis to list: Die Eingabe awird weggelassen, und stattdessen wird der Standardwert des Rückgabetyps verwendet. In seltenen Fällen kann es kürzer als eine rechte Falte sein, zum Beispiel in dieser Antwort .

Als Beispiel für die rekursiven Versionen von mischt Γdie Funktion Γλ·:o⁰↔eine Liste in der Reihenfolge erster, letzter, zweiter, vorletzter, dritter, vorletzter und so weiter. Probieren Sie es online! Die Funktion fist das explizite Lambda λ·:o⁰↔, dessen Argument die gesamte Funktion ist. Was fbedeutet, ist, den Schwanz umzukehren , dann die Hauptfunktion rekursiv mit aufzurufen o⁰und schließlich den Kopf zurückzunageln ·:. Γ·:o₀↔Ist natürlich ein Byte kürzer, funktioniert aber nicht, wenn die Zeile etwas anderes als diese Funktion enthält.

Zgarb
quelle
3

Kombinatoren können auf Funktionen höherer Ordnung angewendet werden

Angenommen, Sie haben eine Liste von Ganzzahlen X und möchten die Gesamtzahl der Elemente von X zählen , die größer als die Länge (X) sind . Das Zählen von Elementen, die ein Prädikat erfüllen, erfolgt mit der Funktion höherer Ordnung #, aber hier hängt das Prädikat (das größer als die Länge (X) ist ) von X ab . Die Lösung besteht darin, den Kombinator auf #und die Funktion anzuwenden, die o>Lüberprüft, ob eine Liste kürzer als eine Zahl ist. In der Funktion Ṡ#o>Lwird die Liste X übergeben o>L, die teilweise angewendete Funktion wird übergeben #und X wird #als zweites Argument übergeben.

Wenn αes sich um eine Funktion höherer Ordnung, βeine Binärfunktion und γeine Unärfunktion Ṡαβhandelt, entspricht dies im Allgemeinen dem Haskell-Pseudocode

\x -> α (\y -> β x y) x

§αβγ ist äquivalent zu

\x -> α (\y -> β x y) (γ x)

und ~αβγist äquivalent zu

\x y -> α (\z -> β x z) (γ y)

solange die Typen übereinstimmen.

§►δṁ≠PFindet als weiteres konkretes Beispiel eine Permutation einer Liste X , die die Summe der absoluten Differenzen zu entsprechenden Werten von X maximiert ( δṁ≠komprimiert zwei Listen unter Verwendung der absoluten Differenz und nimmt die Summe).

Zgarb
quelle
3

Standardwerte von Husk

Husk ist nicht so streng wie Haskell, wo Sie Probleme bekommen, wenn Sie beispielsweise versuchen, das lastElement einer leeren Liste zu erhalten. Um dies zu erreichen, werden vordefinierte Werte verwendet. Hier ist eine Liste der Standardwerte, Maxima und Minima:

.------------------------------------.---------------.----------.-------.
|   Type (X and Y are placeholders)  | default (def) |    max   |  min  |
|------------------------------------|---------------|----------|-------|
|       Character (C)                |      ' '      | \1114111 | \NUL  |
|       Numbers   (N)                |       0       |   Inf    | -Inf  |
|       List of X (LX)               |      []       |  ∞ max   |   []  | *
|       Function :: X -> Y           | const (def Y) |   n/a    |  n/a  |
'------------------------------------'---------------'----------'-------'

* Hier sollte ∞ eine unendliche Liste des entsprechenden Maximums darstellen (siehe unten für ein Beispiel)

Hinweis: Für Tupel (X, Y) werden die Werte für jede Komponente separat verwendet.


Wenn sie benutzt werden

Während die Maxima und Minima nur für ▲▼leere Listen verwendet werden (zum Beispiel husk -u "▼" "[]:LLN"wird eine unendliche Liste von zurückgegeben Inf), werden die Standardwerte an einigen Stellen verwendet:

  • leere Listen umblättern, ohne selbst einen Wert anzugeben ( Fund )
  • Voreinstellung (mit Θ)
  • wenn read ( r) fehlschlägt
  • das erste / letzte Element ( ←→) erhalten oder in eins ( !) indizieren
  • Mustererkennung ( Γ) für leere Listen
  • mit oder auf leeren Listen
ბიმო
quelle