Existe uma maneira de reduzir as funções das setas de gordura?

15

Pelo que eu vi ao longo do meu tempo aqui no PPCG, a maioria das entradas JavaScript envolvendo funções de seta gorda tendem a ser um dos dois campos:

  1. Os simples que são capazes de executar como uma única declaração e retornar uma resposta, logo de cara, como x=(a,b)=>a*a+b

  2. Os mais complexos, que geralmente têm chavetas por causa do uso de loops e, como resultado, exigem o uso de uma returndeclaração.p=b=>{m=b;for(a=1;~-m;)--m,a*=m*m;return a%b}

Tomando o exemplo acima da categoria 2 com o conceito de chaves como prova de conceito ... haveria uma maneira de re-golf este código (ou similar) como este, a fim de eliminar as chaves assim como o return? Só estou perguntando isso, pois isso poderia potencialmente (sem dizer que isso acontecerá o tempo todo) eliminar 8 bytes do código de um jogador de golfe JS. Existem técnicas que alguém poderia usar nesse caso? Eu tentei recursão, mas a m=bdeclaração provou ser um pouco assustadora, pois não consigo mexer.

Para o código acima, como alguém jogaria mais para eliminar a returndeclaração, independentemente de jogar mais ou menos?

WallyWest
fonte

Respostas:

18

Usar recursão

Descobri que a recursão é (quase) sempre menor que eval+ for. A maneira geral de converter de para para eval é:

for(a=n;b;c);d
(f=a=>b?f(c):d)(n)

Então, vamos ver o seu exemplo:

b=>{m=b;for(a=1;~-m;)--m,a*=m*m;return a%b}

Podemos primeiro simplificá-lo para:

for(m=b,a=1;~-m;--m,a*=m*m)a%b;

O que fizemos aqui? Bem, nós simplesmente movemos tudo dentro da fordeclaração, isso nos ajuda a reduzir a quantidade de ponto e vírgula, o que não é diretamente melhor, mas quase sempre leva a um pouco de golfe.


Vamos colocar isso em avaliação e compará-lo com a versão de recursão:

b=>{m=b;for(a=1;~-m;)--m,a*=m*m;return a%b}
b=>eval('for(m=b,a=1;~-m;--m,a*=m*m)a%b')
b=>(f=a=>~-m?(--m,f(a*=m*m)):a%b)(1,m=b)

A primeira parte do loop for ( a=n), podemos começar passando essas variáveis ​​como argumentos. A condição é simplesmente: b?(c,f(a)):donde destá o valor de retorno. Geralmente capenas modifica apara que possa ser mesclado a ele. Para que possamos jogar ainda mais usando o que mencionei:

b=>(f=a=>~-m?(--m,f(a*=m*m)):a%b)(1,m=b)
b=>(f=a=>~-m?f(a*=--m*m):a%b)(1,m=b) // --m moved into a*=
b=>(f=a=>--m?f(a*=m*m):a%b)(1,m=b) // --m moved to condition

Dito isto, como observado por @Niel, está simplificando seu algoritmo. Um algoritmo golfy em um idioma pode não ser golfy em outro, portanto, tente diferentes algoritmos e compare-os.

Downgoat
fonte
1
Você perdeu uma grande economia ao simplificar o código original. ~-mé m-1, para que o loop pode ser for(m=b,a=1;--m;a*=m*m)a%b;ea versão recursiva pode ser (não testado)b=>(f=a=>--m?f(a*=m*m):a%b)(1,m=b)
Peter Taylor
1
Às vezes você apenas tem que usar um algoritmo diferente, mas neste caso o melhor que eu podia fazer era o mesmo comprimento de resposta da @ PeterTaylor:b=>b>1&(f=a=>--a<2||b%a&&f(a))(b)
Neil
11

Avaliação de abuso.

É simples. Ao invés de:

f=n=>{for(i=c=0;i<n;i++)c+=n;return c}

Usar

f=n=>eval("for(i=c=0;i<n;i++)c+=n;c")

Eval retorna a última instrução avaliada. Nesse caso, como seria a última instrução avaliada c+=n, ficaria assim c, economizando dois bytes.

f=n=>eval("for(i=c=0;i<n;i++)c+=n")

Em geral:

f=n=>eval("code;x")

é mais curto que isso, por um byte:

f=n=>{code;return x}

Como uma observação, o uso de sepulturas para chamar eval e possivelmente salvar bytes não funciona, pois:

eval`string`

é equivalente a

["string"]

Útil para ofuscação! Não tanto para o código de golfe.

Conor O'Brien
fonte
2
foo`string`é sempre equivalente a foo(["string"]), é apenas que muitas funções convertem o array de volta na string desejada.
Neil
@ Neil Oh, que interessante!
Conor O'Brien