Conseils pour jouer au golf à Perl 6


16

Quels conseils généraux avez-vous pour jouer au golf à Perl 6? Je recherche des idées qui peuvent être appliquées aux problèmes de golf de code en général qui sont au moins quelque peu spécifiques à Perl 6 (par exemple, "supprimer les commentaires" n'est pas une réponse). Veuillez poster un pourboire par réponse.

Veuillez noter que Perl 6 n'est pas Perl 5, donc cette question n'est pas un doublon. La plupart des conseils pour le golf Perl 5 ne s'appliquent tout simplement pas à Perl 6.

Réponses:


9

Évitez les sublittéraux. Dans de nombreux cas, vous pouvez simplement utiliser {}des blocs de code. Par exemple, n'écrivez pas le code suivant.

sub ($a){$a*2}

Utilisez plutôt la syntaxe des blocs. Cela vous permet également d'utiliser $_, @_et les %_variables d'espace réservé, si vous avez besoin d' une seule variable. Si vous avez besoin de plus, vous pouvez utiliser $^a, les $^bvariables, et ainsi de suite.

{$_*2}

De plus, dans certains cas rares, il est possible d'utiliser n'importe quel code (surtout lorsque vous avez des expressions simples). Le *remplace l'argument d'espace réservé.

* *2

8

Perl 6 a une fonctionnalité vraiment bizarre où il permet à tous les caractères Unicode des catégories Nd , Nl et  No d'être utilisés comme littéraux de nombres rationnels. Certains d'entre eux sont plus courts que l'écriture de leurs valeurs numériques en ASCII:

  • ¼(2 octets) est plus court que .25ou 1/4(3 octets).
  • ¾(2 octets) est plus court que .75ou 3/4(3 octets).
  • (3 octets) est plus court que 1/16(4 octets).
  • 𐦼(4 octets) est plus court que 11/12(5 octets).
  • 𒐲(4 octets) est plus court que 216e3(5 octets).
  • 𒐳(4 octets) est plus court que 432e3(5 octets).

En guise de suivi, vous pouvez également utiliser des exposants Unicode, même avec plusieurs chiffres et / ou un moins: say (3² + 4², 2²⁰, 5⁻²)==> (25 1048576 0.04). La liste complète d'Unicode que vous pouvez abuser comme ceci est ici: docs.perl6.org/language/unicode_texas .
Ramillies

8

Apprenez les fonctions pour lire l'entrée. Perl 6 a de nombreuses fonctions intéressantes qui peuvent facilement lire l'entrée d'ARGV ou STDIN (si rien n'a été spécifié sur ARGV), ce qui peut raccourcir votre code s'il est utilisé correctement. Si vous les appelez en tant que méthodes de STDINdescripteur de fichier , vous pouvez les forcer à travailler sur un descripteur de fichier particulier (utile si vous lisez par exemple , mais que vous devez lire des arguments sur ARGV).

get

Cette fonction obtient une seule ligne et la coupe automatiquement, vous n'avez donc pas à le faire. Ceci est utile si vous devez lire une seule ligne.

lines

Cette fonction récupère toutes les lignes du fichier ou STDIN. C'est une liste paresseuse, donc si vous l'utilisez avec for, elle ne lira que ce dont vous avez besoin. Par exemple.

say "<$_>"for lines

slurp

Cela lira le fichier entier ou STDIN et renverra le résultat sous la forme d'une seule chaîne.


Ce bug a été corrigé - je ne sais pas quand, mais say "<$_>" for linesfonctionne maintenant
cat

5

Avertissement : le mur de texte approche. C'est beaucoup de petites astuces que j'ai rassemblées au fil du temps.

Écrivez vos solutions sous forme de blocs anonymes

Cela a déjà été mentionné, mais je voudrais le répéter. Dans TIO, vous pouvez écrire my $f =dans l'en-tête, le bloc dans le code approprié et démarrer le pied de page avec a ;. Cela semble être de loin le moyen le plus court pour faire le travail (puisque vous n'avez pas besoin de vous soucier de la lecture d'une entrée, elle vous est donnée dans les arguments).

Une autre bonne façon d'utiliser le -nou le -pcommutateur, mais je n'ai pas trouvé de moyen de le faire fonctionner dans TIO.

Utilisez la syntaxe deux-points pour passer des arguments

Autrement dit, au lieu de thing.method(foo,bar), vous pouvez faire thing.method:foo,baret enregistrer 1 caractère. Malheureusement, vous ne pouvez pas appeler une autre méthode sur le résultat pour des raisons évidentes, il est donc logique de ne l'utiliser que pour la dernière méthode d'un bloc.

Utilisez $_autant que vous le pouvez

Il est parfois préférable de prendre un seul argument de liste que plusieurs arguments distincts à cause de cela. Lors de l'accès $_, vous pouvez appeler des méthodes dessus simplement en commençant par un point: eg .sortest égal à $_.sort.

Cependant, gardez à l'esprit que chaque bloc obtient le sien $_, de sorte que les paramètres du bloc externe ne se propageront pas dans les blocs internes. Si vous devez accéder aux paramètres de la fonction principale à partir d'un bloc interne, ...

Utilisez les ^variables si vous ne pouvez pas utiliser$_

Insérez un ^entre le Sigil et le nom de la variable, comme ceci: $^a. Ceux-ci ne fonctionnent qu'à l'intérieur d'un bloc. Le compilateur compte d'abord combien vous en avez dans le bloc, les trie lexicographiquement, puis attribue le premier argument au premier, le second au second et ainsi de suite. Le ^doit être utilisé uniquement lors de la première occurrence de la variable. Prend donc {$^a - $^b}2 scalaires et les soustrait. La seule chose qui compte est l'ordre alphabétique, tout {-$^b + $^a}comme la même chose.

Si jamais vous avez envie d'utiliser la syntaxe de bloc pointu (comme ->$a,$b {$a.map:{$_+$b}}), vous feriez bien mieux d'écrire une déclaration fausse au début du bloc en utilisant le ^pour chaque argument que vous n'allez pas utiliser dans le bloc principal (comme {$^b;$^a.map:{$_+$b}}) (Remarque c'est la meilleure façon de jouer au golf {$^a.map(*+$^b)}. Je voulais juste montrer le concept.)

Lisez attentivement les documents de l' opérateur

Les opérateurs sont très puissants et sont souvent le moyen le plus court de faire avancer les choses. En particulier , les méta-opérateurs (opérateurs qui prennent des opérateurs comme argument) [], [\], X, <</ >>et Zméritent votre attention. N'oubliez pas qu'une méta-op peut prendre comme argument une autre méta-op (comme celle que XZ%%j'ai réussi à utiliser ici ). Vous pouvez également utiliser >>pour un appel de méthode, ce qui peut être beaucoup moins cher qu'une carte ( @list>>.methodau lieu de @list.map(*.method), mais attention, ce n'est pas pareil! ). Et, enfin, avant d'utiliser un binaire << >>, gardez à l'esprit que cela Zfera souvent la même chose avec beaucoup moins de caractères.

Si vous amassez beaucoup de méta-opérations les unes sur les autres, vous pouvez spécifier la priorité à l'aide de crochets []. Cela vous épargnera lorsque vous empilerez autant d'opérateurs que cela confond le compilateur. (Cela n'arrive pas très souvent.)

Enfin, si vous avez besoin de choses à COERCE Bool, Int ou Str, ne pas utiliser les méthodes .Bool, .Intet .Str, mais les opérateurs ?, +et ~. Ou encore mieux, il suffit de les mettre dans une expression arithmétique pour les forcer dans Int et ainsi de suite. Le moyen le plus court pour obtenir la longueur d'une liste est +@list. Si vous voulez calculer 2 à la puissance de la longueur d'une liste, dites simplement 2**@listet cela fera la bonne chose.

Utilisez les variables d'état libre $, @et%

Dans chaque bloc, chaque occurrence de $(ou @ou %) fait référence à une nouvelle variable d'état scalaire (ou tableau ou hachage) brillante (une variable dont la valeur persiste pendant les appels au bloc). Si vous avez besoin d'une variable d'état qui ne doit être référencée qu'une seule fois dans le code source, ces trois sont vos grands amis. (Le plus souvent le $.) Par exemple, dans le défi Cycles mathématiques inversés , il pourrait être utilisé pour choisir les opérateurs de façon cyclique dans un tableau, qui a été indexé par $++%6.

Utilisez les sous-formes de map, grepet al.

Cela signifie: faire plutôt map {my block},listque list.map({my block}). Même si vous parvenez à utiliser list.map:{my block}, ces deux approches sortent au même nombre d'octets. Et souvent, vous devrez mettre la liste entre parenthèses lors de l'appel d'une méthode, mais pas lors de l'appel d'un sous. Ainsi, la sous-approche ressort toujours meilleure ou au moins la même que celle de la méthode.

La seule exception ici est lorsque l'objet qui doit être mapped, grepped et ainsi de suite, est dedans $_. Alors, .map:{}évidemment, bat map {},$_.

Utilisez les jonctions ( &et |) au lieu de &&et ||.

De toute évidence, ils sont plus courts de 1 octet. En revanche, ils doivent s'effondrer en étant contraints dans un contexte booléen. Cela peut toujours être fait avec un ?. Ici, vous devez être conscient d'une méta-op !opqui force le contexte booléen, utilise opet annule le résultat.

Si vous avez une liste et que vous souhaitez la transformer en jonction, n'utilisez pas [&]et [|]. Utilisez plutôt .anyet .all. Il y en a aussi .nonequi ne peuvent pas être si facilement imités par les opérations de jonction.


1
Je pense &&et ||sont toujours utiles pour les courts-circuits?
ASCII uniquement

@ ASCII uniquement: oui, certainement.
Ramillies

4

Réduisez l'espace utilisé pour les variables

Il y a quelques parties à cela.

Supprimer les espaces

Les variables déclarées à l'aide mypeuvent généralement être déclarées sans l'espace entre myet le nom de la variable. my @aest équivalent à my@a.

Utiliser des variables sans cachet

Vous pouvez déclarer des variables à l'aide d'une barre oblique inverse pour supprimer le sceau avant le nom de la variable, comme ceci:

my \a=1;

(malheureusement, vous ne pouvez pas supprimer l'espace :()

Ceci est utile car vous pouvez ensuite vous y référer comme étant simplement le nom de la variable nue.

 a=5;
 a.say

Fondamentalement, cela économise des octets si vous utilisez la variable plus d'une fois ailleurs dans votre code. L'inconvénient est que la variable doit être initialisée.

Utiliser $!et$/

Ces variables pré-déclarées sont généralement utilisées pour les exceptions et les correspondances d'expression rationnelle respectivement, mais n'ont pas besoin d'être définies à l'aide de my.

$!=1;
$/=5;

Il est particulièrement utile d'utiliser $/comme tableau et d'utiliser les raccourcis $suivis d'un nombre pour accéder à cet élément du $/tableau;

$/=100..200;
say $5;  #105
say $99; #199

2

Utiliser ...au lieu defirst

En règle générale, si vous souhaitez trouver le premier nombre correspondant à une condition &f, vous pouvez le représenter comme:

first &f,1..*

Cependant, à la place, vous pouvez utiliser l' ...opérateur:

+(1...&f)

Si vous devez partir de là 0, vous pouvez en avoir -1après au lieu de +.

Si vous voulez que l'index du premier élément d'une liste @aqui ait une condition &f, vous le faites normalement:

first &f,@a,:k

Au lieu:

(@a...&f)-1

(ou vice versa si vous voulez 0 indexé). De la même manière, vous pouvez obtenir tous les éléments jusqu'au premier qui passe la condition.

L'inconvénient est que la liste doit passer la condition à un moment donné, sinon l' ...opérateur tentera d'extrapoler à la fin de la liste et générera très probablement une erreur. Vous ne pouvez pas non plus utiliser n'importe quel code dans la partie gauche, car il serait interprété comme faisant partie de la séquence.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.