Husk é uma linguagem de golfe bastante nova, criada pelos usuários do PPCG Leo e Zgarb . Começou a ser cada vez mais competitivo, muitas vezes ficando próximo ou até superando idiomas conhecidos por serem muito concisos, como Jelly e 05AB1E.
Vamos listar algumas das técnicas de golfe que são um pouco específicas para Husk. Como sempre, poste uma dica por resposta.
Respostas:
Use o valor de retorno dos predicados
Em Husk, funções que testam suas entradas para alguma propriedade geralmente retornam um resultado significativo em casos reais, como qualquer número inteiro positivo é verdade.
Exemplos:
Difference diferença apropriada significa diferença de pontos de código para caracteres. Também se refere à ordem dos argumentos. ou seja
<x y
, para , seriax-y
fonte
Use etiquetas de linha transbordando
Como você já deve saber,
[₀-₉]+|[₀-₉]
é uma expressão regular para a sintaxe chamar uma linha diferente daquela em que você está atualmente.Esta dica é especialmente útil se você quiser que uma função definida em uma linha específica seja chamada como argumento de mais de uma das funções na tabela abaixo ou como argumento para uma ou mais das funções abaixo e por si só.
Tabela de funções:
As linhas no seu código são rotuladas com seus respectivos índices baseados em 0, de cima para baixo. Se M <N , onde M é o rótulo e N é o número de linhas em seu código, o rótulo apenas representa a função definida na linha M . Se N ≤ M <N * 6 , representa a função da tabela acima no índice ⌊M ÷ N⌋ com a função definida na linha M mod N como seu primeiro argumento. Se N * 6 ≤ M , um erro de índice é gerado.
fonte
Lambdas podem ser mais curtas que novas funções
Como você provavelmente sabe se possui um programa de várias linhas, pode consultar as linhas com os subscritos
₀…₉
, por exemplo, no caso de₁
irá se referir à funçãog
. Agora, se você sempre aplicar as entradas à funçãog
(e usá-la várias vezes); algo assim:Você deve introduzir um lambda porque ele economiza 1 byte para cada uso adicional:
O inverso também pode ser verdadeiro
No caso de lambdas autorreferenciais (
φχψ
), há o caso especial em que você aplica as entradas diretamente à função recursiva; nesses casos, é melhor usar o subscrito em₀
vez de definir um novo lambda e usar⁰
.fonte
Usos de
Γ
O principal uso do built-in
Γ
, conhecido como correspondência de padrões em listas ou desconstrução de listas , é dividir uma lista em uma cabeça e cauda e aplicar uma função binária nelas. Corresponde ao idioma correspondente do padrão Haskellonde
<something>
é uma expressão que contémx
,xs
e possivelmentef
. Existem 4 sobrecargas deΓ
, cada uma das quais funciona um pouco diferente.list
A primeira sobrecarga,
list
assume um valora
e uma função bináriaf
. Ele retorna uma nova função que pega uma lista, retornaa
se estiver vazia e chamaf
a cabeça e a cauda se não estiver vazia. Por exemplo,Γ_1€
pega uma lista, retorna-1
se estiver vazia e o índice da primeira ocorrência do primeiro elemento na cauda, se não estiver.listN
A segunda sobrecarga,,
listN
é semelhante alist
, exceto quea
é omitida e o valor padrão do tipo de retorno é usado. Por exemplo,Γ€
é equivalente aΓ0€
, já que o valor numérico padrão é0
.Na prática,
listN
é usado com mais frequência do quelist
, uma vez que o valor padrão é irrelevante ou exatamente o que você precisa. Um padrão comum éΓ~αβγ
ondeαβγ
estão três funções; isso se aplicaβ
ao primeiro elemento eγ
à cauda e combina os resultados comα
. Foi usado, por exemplo, nesta resposta . Outros padrões incluemΓo:α
a aplicaçãoα
apenas ao primeiro elemento eΓ·:mα
a aplicaçãoα
a todos os elementos, exceto o primeiro. O último foi usado nesta resposta .listF
A terceira sobrecarga é um pouco mais envolvida. Como
list
, é preciso um valora
e uma funçãof
e retorna uma nova funçãog
que leva uma lista. No entanto, esse tempof
exige um argumento de função extra, que ég
ele próprio, e pode chamá-lo com qualquer valor (incluindo, mas não limitado a, final da lista de entrada). Isso significa quelistF
implementa um esquema geral de recursão nas listas.listF
não é usado com muita frequência, pois a recursão explícita comlist
/listN
geralmente é do mesmo tamanho ou menor, como nesta resposta .listNF
listNF
é para olistF
quelistN
élist
: a entradaa
é omitida e o valor padrão do tipo de retorno é usado. Em raras circunstâncias, pode ser menor que uma dobra à direita, por exemplo, nesta resposta .Como exemplo das versões recursivas de
Γ
, a funçãoΓλ·:o⁰↔
embaralha uma lista na ordem primeiro, último, segundo, penúltimo, terceiro, penúltimo e assim por diante. Experimente online! A funçãof
é a lambda explícitaλ·:o⁰↔
, cujo argumento⁰
é a função inteira. O quef
faz é inverter a cauda com↔
, em seguida, chame a função principal recursivamente como⁰
e finalmente enfie a cabeça para trás·:
. Obviamente,Γ·:o₀↔
é um byte mais curto, mas não funciona se a linha contiver algo além dessa função.fonte
Os combinadores podem ser aplicados a funções de ordem superior
Suponha que você tenha uma lista de números inteiros X e queira contar o número total de elementos de X maiores que o comprimento (X) . Elementos de contagem que satisfazem um predicado é feito com a função de ordem superior
#
, mas aqui o predicado (sendo maior do que o comprimento (X) ) depende de X . A solução é aplicar a combinatorṠ
para#
ea funçãoo>L
que verifica se a lista é mais curto do que um número. Na funçãoṠ#o>L
, a lista X é passada parao>L
, a função parcialmente aplicada é passada#
e X é fornecido#
como o segundo argumento.Em geral, se
α
é uma função de ordem superior,β
uma função binária eγ
uma função unária,Ṡαβ
é equivalente ao pseudocódigo de Haskell§αβγ
é equivalente ae
~αβγ
é equivalente adesde que os tipos correspondam.
Como outro exemplo concreto,
§►δṁ≠P
encontra uma permutação de uma lista X que maximiza a soma das diferenças absolutas para os valores correspondentes de X (δṁ≠
fecha duas listas usando a diferença absoluta e recebe a soma).fonte
Valores padrão do Husk
Husk não é tão rigoroso quanto Haskell, onde você encontra problemas quando, por exemplo, tenta obter o
last
elemento de uma lista vazia. Para conseguir isso, ele usa valores predefinidos, aqui está uma lista dos valores padrão, máximos e mínimos:* Aqui ∞ deve representar uma lista infinita do máximo correspondente (veja um exemplo abaixo)
Nota: Para tuplas (X, Y), os valores de cada componente serão utilizados separadamente.
Quando eles são usados
Enquanto o máximo e o mínimo são usados apenas
▲▼
em listas vazias (por exemplohusk -u "▼" "[]:LLN"
, retornará uma lista infinita deInf
), os valores padrão são usados em alguns lugares:F
eḞ
)Θ
)r
) falha←→
) ou indexando em um (!
)Γ
) em listas vazias►
ou◄
em listas vaziasfonte