Dicas para jogar golfe em Perl 6


16

Que dicas gerais você tem para jogar golfe no Perl 6? Estou procurando idéias que possam ser aplicadas aos problemas de código de golfe em geral que sejam pelo menos um pouco específicos para o Perl 6 (por exemplo, "remover comentários" não é uma resposta). Poste uma dica por resposta.

Observe que o Perl 6 não é o Perl 5, portanto, essa pergunta não é uma duplicata. A maioria das dicas para jogar golfe no Perl 5 simplesmente não se aplica ao Perl 6.

Respostas:


9

Evite subliterais. Em muitos casos, você pode simplesmente usar {}para blocos de código. Por exemplo, não escreva o código a seguir.

sub ($a){$a*2}

Em vez disso, use a sintaxe dos blocos. Isso também permite que você use $_, @_e %_variáveis de espaço reservado, se você só precisa de uma única variável. Se precisar de mais, você pode usar $^a, $^bvariáveis, e assim por diante.

{$_*2}

Além disso, em alguns casos raros, é possível usar qualquer código (especialmente quando você tem expressões simples). O *substitui o argumento do espaço reservado.

* *2

8

O Perl 6 possui um recurso muito bizarro, onde permite todos os caracteres Unicode nas categorias Nd , NlNo sejam usados ​​como literais numéricos racionais. Alguns deles são mais curtos do que escrever seus valores numéricos em ASCII:

  • ¼(2 bytes) é menor que .25ou 1/4(3 bytes).
  • ¾(2 bytes) é menor que .75ou 3/4(3 bytes).
  • (3 bytes) é menor que 1/16(4 bytes).
  • 𐦼(4 bytes) é menor que 11/12(5 bytes).
  • 𒐲(4 bytes) é menor que 216e3(5 bytes).
  • 𒐳(4 bytes) é menor que 432e3(5 bytes).

Como acompanhamento para isso, você também pode usar expoentes Unicode, mesmo com vários dígitos e / ou menos: say (3² + 4², 2²⁰, 5⁻²)==> (25 1048576 0.04). A lista completa de Unicode que você pode abusar assim está aqui: docs.perl6.org/language/unicode_texas .
Ramillies

8

Aprenda as funções para ler a entrada. O Perl 6 possui muitas funções interessantes que podem facilmente ler a entrada do ARGV ou STDIN (se nada foi especificado no ARGV), que pode encurtar o seu código se usado corretamente. Se você os chamar como métodos de STDINtratamento de arquivos , poderá forçá-los a trabalhar em um tratamento de arquivo específico (útil se, por exemplo , você ler , mas precisar ler argumentos no ARGV).

get

Essa função obtém uma única linha e a mastiga automaticamente, para que você não precise. Isso é útil se você precisar ler apenas uma linha.

lines

Esta função obtém todas as linhas do arquivo ou STDIN. É uma lista lenta, por isso, se você a usar for, ela lerá apenas o que você precisa. Por exemplo.

say "<$_>"for lines

slurp

Isso lerá o arquivo inteiro ou STDIN e retornará o resultado como uma única sequência.


Esse bug foi corrigido - não sei quando, mas say "<$_>" for linesfunciona agora #
cat

5

Aviso : parede de texto se aproximando. São muitos truques pequenos que reuni ao longo do tempo.

Escreva suas soluções como blocos anônimos

Isso já foi mencionado, mas eu gostaria de reiterar. No TIO, você pode escrever my $f =no cabeçalho, o bloco no código apropriado e iniciar o rodapé com a ;. Essa parece ser de longe a maneira mais curta de realizar o trabalho (já que você não precisa se preocupar em ler nenhuma entrada, ela é fornecida nos argumentos).

Outra maneira interessante é usar o switch -nou o -pswitch, mas não encontrei uma maneira de fazê-lo funcionar no TIO.

Use a sintaxe dos dois pontos para passar argumentos

Ou seja, em vez de thing.method(foo,bar), você pode fazer thing.method:foo,bare salvar 1 caractere. Infelizmente, você não pode chamar outro método no resultado por razões óbvias; portanto, faz sentido usar apenas o último método em um bloco.

Use $_o máximo que puder

Às vezes, é melhor usar um argumento de lista única do que vários argumentos separados por causa disso. Ao acessar $_, você pode chamar métodos apenas começando com um ponto: por exemplo, .sorté igual a$_.sort .

No entanto, lembre-se de que cada bloco recebe o seu $_, para que os parâmetros do bloco externo não se propaguem para os internos. Se você precisar acessar os parâmetros da função principal a partir de um bloco interno, ...

Use as ^variáveis ​​se você não puder usar$_

Inserir um ^entre o sigilo eo nome da variável, como este: $^a. Estes funcionam apenas dentro de um bloco. O compilador primeiro conta quantas delas você possui no bloco, as classifica lexicograficamente e depois atribui o primeiro argumento ao primeiro, o segundo ao segundo e assim por diante. O ^precisa ser usado apenas na primeira ocorrência da variável. Então {$^a - $^b}pega dois escalares e os subtrai. A única coisa que importa é a ordem alfabética, {-$^b + $^a}o mesmo acontece.

Se você sentir vontade de usar a sintaxe do bloco pontudo (como ->$a,$b {$a.map:{$_+$b}}), é muito melhor escrever uma declaração falsa no início do bloco usando o ^para cada argumento que não será usado no bloco principal (como {$^b;$^a.map:{$_+$b}}) (Observação) essa é a melhor maneira de jogar golfe {$^a.map(*+$^b)}. Eu só queria mostrar o conceito.)

Leia atentamente os documentos do operador

Os operadores são muito poderosos e geralmente são a maneira mais curta de fazer as coisas. Especialmente os meta-operadores (operadores que levam operadores como um argumento) [], [\], X, <</ >>e Zvalem de sua atenção. Não esqueça que uma meta-op pode XZ%%usar outra meta-op como argumento (como uma que eu consegui usar aqui ). Você também pode usar >>uma chamada de método, que pode ser muito mais barata que um mapa (em @list>>.methodvez de @list.map(*.method), mas cuidado, elas não são iguais! ). E, finalmente, antes de usar um binário << >>, lembre-se de que Zmuitas vezes fará a mesma coisa em muito menos caracteres.

Se você agrupar várias meta-ops, poderá especificar a precedência usando colchetes []. Isso economizará você quando você empilha tantos operadores que confunde o compilador. (Isso não acontece com muita frequência.)

Finalmente, se você precisa de coisas coagir a Bool, Int ou Str, não use os métodos .Bool, .Inte .Str, mas sim os operadores ?, +e ~. Ou melhor ainda, basta colocá-los em uma expressão aritmética para forçá-los a Int e assim por diante. A maneira mais curta de obter o comprimento de uma lista é +@list. Se você deseja calcular 2 com base no comprimento de uma lista, basta dizer 2**@liste ele fará a coisa certa.

Use as variáveis de estado livre $, @e%

Em cada bloco, toda ocorrência de $(ou @ou %) refere-se a uma nova variável de estado escalar (ou matriz ou hash) brilhante (uma variável cujo valor persiste nas chamadas para o bloco). Se você precisar de uma variável de estado que precise ser referenciada apenas uma vez no código-fonte, esses três serão seus grandes amigos. (Na maioria das vezes, o $.) Por exemplo, no desafio Ciclos matemáticos reversos , ele poderia ser usado para escolher os operadores ciclicamente a partir de uma matriz, que foi indexada por $++%6.

Use as sub-formas de map, grepet al.

Isso significa: faça em vez map {my block},listde list.map({my block}). Mesmo se você conseguir usar list.map:{my block}, essas duas abordagens serão exibidas no mesmo número de bytes. E, frequentemente, você precisaria colocar parênteses na lista ao chamar um método, mas não ao chamar um sub. Portanto, a sub abordagem é sempre melhor ou pelo menos a mesma do método.

A única exceção aqui é quando o objeto que deve ser mapped, grepped e assim por diante, é no $_. Então, .map:{}obviamente, bate map {},$_.

Use junções ( &e |) em vez de &&e ||.

Obviamente, eles são 1 byte mais curto. Por outro lado, eles devem ser recolhidos ao serem forçados a um contexto booleano. Isso sempre pode ser feito com a ?. Aqui você deve estar ciente de uma meta-op !opque força o contexto bool, usa ope nega o resultado.

Se você tem uma lista e deseja transformá-la em uma junção, não use [&]e [|]. Em vez disso, use .anye .all. Há também os .noneque não podem ser tão facilmente imitados pelas operações de junção.


11
Penso &&e ||ainda são úteis para curtos-circuitos?
somente ASCII

@ Somente ASCII: Sim, certamente eles são.
Ramillies

4

Reduza o espaço usado para variáveis

Há algumas partes nisso.

Remover espaço em branco

As variáveis ​​declaradas usando mygeralmente podem ser declaradas sem o espaço entre mye o nome da variável. my @aé equivalente a my@a.

Use variáveis ​​sem sigilo

Você pode declarar variáveis ​​usando uma barra invertida para remover o sigil antes do nome da variável, assim:

my \a=1;

(infelizmente você não pode remover o espaço :()

Isso é útil, pois você pode consultá-los apenas como o nome da variável simples posteriormente.

 a=5;
 a.say

Basicamente, isso salva bytes se você usar a variável mais de uma vez em outro lugar do seu código. A desvantagem é que a variável precisa ser inicializada.

Use $!e$/

Essas variáveis ​​pré-declaradas geralmente são usadas para exceções e correspondências de regex, respectivamente, mas não precisam ser definidas usando my.

$!=1;
$/=5;

Especialmente útil é usar $/como uma matriz e usar os atalhos $seguidos por um número para acessar esse elemento da $/matriz;

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

2

Use em ...vez defirst

Normalmente, se você deseja encontrar o primeiro número que corresponde a alguma condição &f, pode representá-lo como:

first &f,1..*

No entanto, você pode usar o ...operador:

+(1...&f)

Se você tiver que começar 0, poderá ter -1depois em vez de +.

Se você deseja o índice do primeiro elemento em uma lista @aque possui condição &f, normalmente você faz:

first &f,@a,:k

Em vez de:

(@a...&f)-1

(ou vice-versa, se você quiser 0 indexado). Da mesma forma, você pode obter todos os elementos até o primeiro que passa na condição.

O lado negativo disso é que a lista precisa passar a condição em algum momento; caso contrário, o ...operador tentará extrapolar o final da lista e provavelmente causará um erro. Você também não pode usar o código Whatever no lado esquerdo, pois ele seria interpretado como parte da sequência.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.