Dicas para jogar golfe em K


17

K é uma linguagem de programação da família APL projetada por Arthur Whitney. Enquanto o intérprete oficial é de código fechado e comercial, uma versão de avaliação com um limite de espaço de trabalho de 32 bits de espaço de endereçamento (que não deve representar problemas para o código de golfe) pode ser encontrada no site da Kx Systems . Esta versão do pacote como parte do banco de dados kdb + é conhecida coloquialmente como "K4". Também existem implementações de código-fonte K disponíveis, incluindo o Kona , que é baseado no K3, e meu próprio intérprete chamado oK , que é baseado no K5 e tem um REPL baseado no navegador .

A Kx Systems possui um wiki com informações sobre o K4 / kdb + / Q, e a página do Kona GitHub também possui uma excelente coleção de materiais de referência. Comecei a escrever um manual para oK / k5, que pode ser uma referência útil.

Como J e APL, K é uma linguagem muito concisa e poderosa, e geralmente pode ser uma boa exibição no código de golfe. Compartilhe dicas, truques e idiomas que você descobrir e, se você ainda não experimentou o K, considere dar uma olhada! Poste uma dica por resposta, por favor!

Respostas:


5

Chamando uma díade

Supondo que você tivesse uma função diádica (2 argumentos) f:

f: {x+2*y}

Você normalmente chamaria assim:

f[3;47]

Você pode salvar um caractere, em vez disso, currying no primeiro argumento e, em seguida, aplicando a função parcial resultante ao segundo argumento por justaposição:

f[3]47

O mesmo naturalmente funciona para a indexação de array:

  z: (12 17 98;90 91 92)
(12 17 98
 90 91 92)

  z[1;2]
92

  z[1]2
92

5

Imprimir novas linhas

Se sua saída precisa ter uma nova linha, você pode ser tentado a fazer isso:

`0:whatever,"\n"

Não . O K2 (e provavelmente outras versões) possui um recurso interessante, onde você pode imprimir uma lista de linhas:

  `0:("abc";"def")
abc
def

Portanto, se você precisar anexar uma nova linha à saída, faça:

`0:,whatever

3

Gamas

Normalmente, se você deseja criar um vetor de números sequenciais, você usa ! :

  !5
0 1 2 3 4

Se você deseja criar um intervalo que comece com um número diferente de zero, adicione um deslocamento ao vetor resultante:

  10+!5
10 11 12 13 14

Existem algumas abordagens incomuns que podem funcionar melhor para uma situação específica. Por exemplo, se sua base e deslocamento já são membros de uma lista, você pode usar "where" duas vezes:

  &10 5
0 0 0 0 0 0 0 0 0 0 1 1 1 1 1
  &&10 5
10 11 12 13 14

Para sequências de crescimento mais lento, considere combinar "where" com "take":

  5#2
2 2 2 2 2
  &5#2
0 0 1 1 2 2 3 3 4 4

Se você deseja criar um intervalo de múltiplos, você pode multiplicar o resultado !ou digitalizar ( \) uma lista de cópias do tamanho da etapa:

  2*!5
0 2 4 6 8
  +\5#2
2 4 6 8 10

Se você estiver tentando evitar parênteses, o primeiro será melhor se o comprimento da sequência for variável e o tamanho da etapa for fixo, enquanto o último será melhor se o tamanho da etapa for o que tende a variar. Escolher a variação certa pode salvar 1 ou 2 caracteres. A diferença de um por um também pode funcionar a seu favor.


2

Moldes de cordas são caros. Basta usar eval. Este:

0.0$a

pode se tornar exatamente isso:

. a

No K5, é um byte mais curto:

.a

2

Cada Direito

Ocasionalmente, você pode encontrar-se escrevendo (ou chegando por simplificação) uma expressão entre parênteses aplicada por meio de cada mônada:

  (2#)'3 4 5
(3 3
 4 4
 5 5)

É um caractere mais curto para converter esse padrão em um aplicativo de cada direito:

  2#/:3 4 5
(3 3
 4 4
 5 5)

1

Permutações cíclicas

Diádico !em K3 / K4 é "rotação":

  2!"abcd"
"cdab"
  -1!"abcd"
"dabc"

Quando "scan" ( \) é fornecido com um verbo monádico, ele atua como um operador de ponto fixo. Em K, os operadores de ponto fixo repetidamente aplicam seu verbo a um valor até que o valor inicial seja revisado ou o valor pare de mudar. A combinação de rotação e varredura de ponto fixo fornece uma maneira muito conveniente de calcular um conjunto de permutações cíclicas de uma lista:

  ![1]\1 2 4 8
(1 2 4 8
 2 4 8 1
 4 8 1 2
 8 1 2 4)

Você pode curry !entre colchetes ou parênteses para criar o trem verbal (1!):

![1]\
(1!)\

(Observe que 1!\ possui um comportamento totalmente diferente!). Cada um deles é equivalente em comprimento, mas o primeiro pode ser mais desejável se o passo de rotação for algo diferente de 1; nesse caso, os colchetes delimitam uma subexpressão entre parênteses "de graça".

Como exemplo, aqui está um pequeno programa que testa via força bruta se uma string x contém a subcadeia y (ciclicamente!):

{|/(y~(#y)#)'![1]\x}

Usuários do K5, cuidado! K5 mudou o significado de diádico !, então essa técnica não é tão fácil. Funcionará como esperado em Kona.


1

Evitar condicionais

K tem uma construção condicional ( :[) que é equivalente a um estilo Lisp cond:

:[cond1;result1; cond2;result2; cond3;result3; default]

Você pode ter quantas condições desejar e se nenhuma corresponder ao valor padrão será retornado.

Às vezes (como em programas recursivos ou em programas que dependem de uma sequência de efeitos colaterais), não há como usar um desses. No entanto, em situações nas quais você pode se dar ao luxo de fazer um pouco de trabalho extra, geralmente é possível substituir um "cond" pela indexação de lista.

Considere o infame programa fizzbuzz . Escrito em um estilo de programação imperativa convencional, podemos incluir:

{:[~x!15;"FizzBuzz";~x!3;"Fizz";~x!5;"Buzz";x]}'1+!100

Há bastante repetição aqui nos testes de divisibilidade. Uma abordagem diferente reconhece que existem 4 casos (um número, divisibilidade por apenas 3, divisibilidade por apenas 5, divisibilidade por 3 e 5) e tenta calcular diretamente um índice que escolhe um desses casos em uma lista:

{(x;"Fizz";"Buzz";"FizzBuzz")@+/1 2*~x!/:3 5}'1+!100

Dois caracteres mais curtos e um melhor uso do idioma. Sabendo que os literais da lista são avaliados da direita para a esquerda, também obtemos algumas oportunidades adicionais de golfe para combinar subexpressões reutilizadas. Não poderíamos ter feito isso facilmente na versão baseada em cond, pois os casos de cadeia de caracteres não são avaliados se não estiverem selecionados:

{(x;4#t;4_ t;t:"FizzBuzz")@+/1 2*~x!/:3 5}'1+!100

Agora, salvamos 5 caracteres no total. Aliás, este exemplo em particular é ainda melhor no k5, pois temos a sobrecarga do "pacote" para /lidar com a etapa de multiplicação por um vetor de coeficientes e somatórios:

{(x;4_t;4#t;t:"FizzBuzz")@2 2/~3 5!\:x}'1+!100

Observe também que o comportamento de "find" ( ?), que produz um índice após o final da lista de chaves, se o item não for encontrado, foi projetado especificamente para suportar o tratamento de um caso "padrão" nesse tipo de indexação. Considere este fragmento para converter vogais em maiúsculas:

{("AEIOU",x)"aeiou"?x}'

Contra um de:

{t:"aeiou"?x;:[t<5;"AEIOU"t;x]}'
{:[~4<t:"aeiou"?x;"AEIOU"t;x]}'

(Eu sei o que eu prefiro ler também!)

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.