Conoce tus argumentos de función pura
Al jugar al golf, a menudo empleará un enfoque funcional, en el que utiliza funciones anónimas (puras) con la &
sintaxis abreviada. Hay muchas maneras diferentes de acceder a los argumentos de una función de este tipo, y a menudo puede reducir un par de bytes al tener un buen conocimiento de las posibilidades.
Acceso a argumentos únicos
Probablemente lo sepas si has usado funciones puras antes. El n º argumento se denomina #n
, y #
actúa como un alias para #1
. Entonces, si, por ejemplo, desea escribir una función que tome como parámetros otra función y su argumento (para pasar el argumento a esa función), use
#@#2&
Esto no funciona con números negativos (como los que podría usar al acceder a las listas).
Acceso a argumentos con nombre (nuevo en V10)
Una de las principales características nuevas del lenguaje en Mathematica 10 es Association
s, que son básicamente mapas de valores clave con tipos de clave arbitrarios, escritos como
<| x -> 1, "abc" -> 2, 5 -> 3 |>
Si dicha asociación se pasa como primer argumento a una función pura, puede acceder a algunos de sus argumentos como parámetros con nombre:
{#, #2, #3, #abc, #xyz} & [<| "abc" -> "1st", "xyz" -> "2nd", abc -> "3rd" |>, "4th", "5th"]
(* {<| "abc" -> "1st", "xyz" -> "2nd", abc -> "3rd" |>, "4th", "5th", "1st", "2nd"} *)
Tenga en cuenta que #
todavía se refiere a toda la asociación como se esperaba. Para que los parámetros nombrados funcionen, las claves deben ser cadenas (no funcionará si utiliza variables indefinidas, por ejemplo), y esas cadenas deben comenzar con una letra y solo contener letras y dígitos.
El argumento del "yo" #0
Una característica menos conocida es que #0
también existe y le proporciona el objeto de función en sí. Esto puede ser realmente útil en quines y quines generalizados. De hecho, la quine más corta de Mathematica (que conozco) es
ToString[#0][] & []
Lo que es un poco molesto es que no te dará los caracteres exactos que ingresaste. Por ejemplo, si se usa @
para la aplicación de funciones, todavía se representará como [...]
y se insertarán espacios en algunos lugares. Esto generalmente hará que la quine sea un poco más larga de lo que le gustaría, pero siempre funcionará, primero jugando al quine y luego simplemente copiando su salida, que ahora debería ser una quine real.
Además de quines, esto también significa que puede escribir código recursivo sin tener que nombrar su función. Compare estas tres implementaciones de Fibonacci (ingenuas pero golfistas):
f@0=0;f@1=1;f@n_:=f[n-1]+f[n-2]
f@n_:=If[n<2,n,f[n-1]+f[n-2]]
If[#<2,#,#0[#-1]+#0[#-2]]&
Secuencias de argumentos
Ahora aquí es donde comienza la verdadera magia. Las secuencias no se usan a menudo en el golf, porque Sequence
es un nombre demasiado largo para que valga la pena la mayor parte del tiempo. Pero en las funciones puras es donde brillan. Si no está familiarizado con las secuencias, básicamente son como símbolos en algunos otros idiomas, si usa una secuencia en una List
lista de argumentos de una función, sus elementos se expandirán automáticamente en ranuras separadas. Asi que
{1, Sequence[2, 3, 4], 5} == {1, 2, 3, 4, 5}
f["a", Sequence[0, {}], "b"] == f["a", 0, {}, "b"]
Ahora, en funciones puras ##
o ##1
es una secuencia de todos los argumentos. Del mismo modo, ##2
es una secuencia de todos los argumentos que comienzan desde el segundo, ##3
todos los argumentos que comienzan desde el tercero, etc. Entonces, para empezar, podemos volver a implementar Sequence
como ##&
, ahorrando 5 bytes. Como ejemplo de uso, esto nos proporciona una alternativa a Join@@list
(vea este consejo ), que no guarda ningún byte, pero es bueno saber de todos modos:
##&@@@list
Esto efectivamente aplana el primer nivel de una lista anidada. ¿Qué más podemos hacer con esto? Aquí hay una alternativa más corta de 2 bytes para RotateLeft
:
RotateLeft@list
{##2,#}&@list
Solo por estas cosas vale la pena tener en cuenta esta característica. Sin embargo, podemos hacerlo mejor! Las secuencias se vuelven realmente interesantes cuando se considera que los operadores se implementan realmente como funciones ocultas. Por ejemplo, en a+b
realidad evalúa a Plus[a,b]
. Entonces, si le damos una secuencia ...
1+##&[1,2,3]
=> Plus[1,##]
=> Plus[1,1,2,3]
=> 7
Este truco se ha utilizado en este consejo para guardar un byte Times
, porque técnicamente la yuxtaposición también es solo un operador:
1##&[1,2,3]
=> Times[1,##]
=> Times[1,1,2,3]
=> 6
También puede usarlo para guardar un byte Unequal
si tiene un valor o variable de un solo carácter que sabe que no está en sus argumentos ( N
probablemente funcionará en el 99% de los casos):
Unequal[a,b,c]
N!=##&[a,b,c]
Esto se vuelve aún más interesante con los operadores unarios y -
y /
- los dos últimos se llevan a la práctica los términos de la multiplicación y exponenciación. Aquí hay una lista de cosas que puede hacer, donde la última columna asume que la función pasó los argumentos a, b, c
:
Operator Function Expanded Equivalent to
+## Plus[##] Plus[a,b,c] a+b+c
1## Times[1,##] Times[1,a,b,c] a*b*c
-## Times[-1,##] Times[-1,a,b,c] -a*b*c
x+## Plus[x,##] Plus[x,a,b,c] x+a+b+c
x-## Plus[x,Times[-1,##]] Plus[x,Times[-1,a,b,c]] x-a*b*c
x## Times[x,##] Times[x,a,b,c] x*a*b*c
x/## Times[x,Power[##,-1]] Times[x,Power[a,b,c,-1]] x*a^b^c^-1
##/x Times[##,Power[x,-1]] Times[a,b,c,Power[x,-1]] a*b*c/x
x^## Power[x,##] Power[x,a,b,c] x^a^b^c
##^x Power[##,x] Power[a,b,c,#] a^b^c^x
x.## Dot[x,##] Dot[x,a,b,c] x.a.b.c
Otros operadores son comunes !=
, ==
, &&
, ||
. Menos comunes a tener en cuenta son |
, @*
, /*
. Para concluir, aquí hay un pequeño truco extra:
#### Times[##,##] Times[a,b,c,a,b,c] (a*b*c)^2
¡Siga experimentando con estos y avíseme si encuentra otras aplicaciones útiles o particularmente interesantes!
(Norm[#-#2]&)
en lugar deEuclideanDistance
.