¿Hay alguna forma de acortar las funciones de flecha de grasa?

15

Por lo que he visto durante mi tiempo aquí en PPCG, la mayoría de las entradas de JavaScript que involucran funciones de flecha gruesa tienden a ser uno de dos campos:

  1. Los simples que son capaces de ejecutarse como una sola declaración y devolver una respuesta, de inmediato, como x=(a,b)=>a*a+b

  2. Los más complejos que generalmente tienen llaves debido al uso de bucles, y como resultado requieren el uso de una returndeclaración ... comop=b=>{m=b;for(a=1;~-m;)--m,a*=m*m;return a%b}

Tomando el ejemplo anterior de la categoría 2 con el concepto de llaves como prueba de concepto ... ¿Habría una forma de re-golf este código (o similar) como este para eliminar las llaves y el return? Solo pregunto esto, ya que esto podría potencialmente (sin decir que esto sucederá todo el tiempo) eliminar 8 bytes del código de un golfista JS. ¿Hay alguna técnica que se pueda usar en este caso? He intentado la recursividad, pero la m=bdeclaración ha demostrado ser un poco aburrida, ya que parece que no puedo sacudirla.

Para el código anterior, ¿cómo se puede jugar más golf para eliminar la returnafirmación, independientemente de si el golf es más corto o no?

WallyWest
fuente

Respuestas:

18

Usar recursividad

Descubrí que la recursividad es (casi) siempre más corta que eval+ for. La forma general de convertir de for a eval es:

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

Así que veamos tu ejemplo:

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

Primero podemos simplificarlo a:

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

Que hicimos aqui Bueno, simplemente movimos todo dentro de la fordeclaración, esto nos ayuda a reducir la cantidad de punto y coma que no es directamente mejor, pero casi siempre conduce a algo de golf.


Pongamos esto en eval y compárelo con la versión de recursión:

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)

La primera parte del bucle for ( a=n), podemos comenzar pasando esas variables como argumentos. La condición es simplemente: b?(c,f(a)):ddónde destá el valor de retorno. Por clo general, solo se modifica apara que pueda fusionarse en él. Para que podamos jugar golf aún más usando lo que he mencionado:

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

Dicho esto, como señaló @Niel, está simplificando su algoritmo. Un algoritmo de golf en un idioma puede no serlo en otro, así que asegúrese de probar diferentes algoritmos y compararlos.

Downgoat
fuente
1
Te has perdido un gran ahorro al simplificar el código original. ~-mes decir m-1, el bucle puede ser for(m=b,a=1;--m;a*=m*m)a%b;y la versión recursiva puede ser (no probada)b=>(f=a=>--m?f(a*=m*m):a%b)(1,m=b)
Peter Taylor
1
A veces solo tiene que usar un algoritmo diferente, pero en este caso lo mejor que pude hacer fue la misma longitud que la respuesta de @ PeterTaylor:b=>b>1&(f=a=>--a<2||b%a&&f(a))(b)
Neil
11

Abuso eval.

Es simple. En lugar de:

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

Utilizar

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

Eval devuelve la última declaración evaluada. En este caso, dado que la última declaración evaluada sería c+=n, nos quedaría de ctodos modos, ahorrando dos bytes.

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

En general:

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

es más corto que esto, por un byte:

f=n=>{code;return x}

Como nota, el uso de tumbas para llamar a eval para posiblemente guardar bytes no funciona, ya que:

eval`string`

es equivalente a

["string"]

Útil para la ofuscación! No tanto por el código de golf.

Conor O'Brien
fuente
2
foo`string`siempre es equivalente a foo(["string"]), es solo que muchas funciones luego vuelven la matriz a la cadena deseada.
Neil
@Neil ¡Oh, qué interesante!
Conor O'Brien