Consejos para jugar golf en APL

28

Empecé un desafío de golf de código recientemente y parece que el ganador es GolfScript (¡sorpresa, sorpresa!). Lo interesante es que había otro competidor muy fuerte que tenía todas las posibilidades de ganarse a GolfScript. Se llama APL. Veo muchas respuestas escritas en APL aquí. Parece que este lenguaje es bastante eficiente para el golf de código, por lo que decido pedir cualquier consejo de golf de código que conozca para los programas APL. Siéntase libre de publicar algunos ejemplos de código. Suele ser muy interesante ver el lenguaje en acción.

gthacoder
fuente

Respuestas:

23

Editar : para las personas que leen esto y que no conocen APL pero quieren aprenderlo, Mastering Dyalog APL es un muy buen recurso.

  1. La evaluación es estrictamente de derecha a izquierda. Esto incluye la configuración de variables, así que aprovéchalo.

    2+a, 1+a←1 -> 3 4

    aestá establecido en 1, 1+aevalúa en 2, a,2evalúa en 1 2y 2+1 2evalúa en 3 4.

  2. Al igual que C, se puede combinar con una función, es decir a +← 3. A diferencia de C, esto es genérico: se foo F← barestablece fooen F bar. Algo poco intuitivo, como expresión, esto regresa bar, no F bar.

    También funciona con funciones anónimas:

          a←0
          a+←3 ⋄ a
    3
          a+←3 ⋄ a
    6
          a { ⍵/'!' } ←4 ⋄ a
    !!!!
    
  3. Puede asignar a una matriz: A[3]←8como esperaría. Pero también puede asignar varios elementos al mismo tiempo: A[3 5 6]←9 1 4o incluso A[3 5 6]←9configurarlos en el mismo elemento. Por supuesto, también puede agregar una función al aquí. La función se aplicará a cada elemento por separado, como si lo hiciera .

  4. es tu amigo, incluso si no se ve muy feliz por eso.

    1. Si Fes diádico, diádico cambia los argumentos: a F b<-> b F⍨ a. Esto es útil cuando juega golf porque puede salvarlo del uso de aparatos ortopédicos:

      (F G H x) K y      <->     y K⍨ F G H x
      

      Esto cambia el orden de evaluación, ya que la mano derecha siempre se evalúa antes que la mano izquierda.

    2. Si Fes diádico, monádico aplica el mismo argumento a ambos lados de la función:

            5⍴5
      5 5 5 5 5
            ⍴⍨5
      5 5 5 5 5
      

      El argumento solo se evalúa una vez. Esto es particularmente útil con productos externos, es decir, para comparar cada valor en una matriz con los otros valores en la misma matriz, puede usar en ∘.=⍨lugar de tener que hacerlo x∘.=x←(whatever).

    3. Si Fes monádico, no hace nada, pero separa la función del argumento. Por lo tanto, aún puede ahorrarle llaves si la función es compleja:

            {⍵+3}⍣5 6
            ∇{⍵+3}              
           ∇ ⍣ 5 6              
            ({⍵+3}⍣5)6
      21
            {⍵+3}⍣5⍨6
      21
      
  5. ¡Aprende los modismos! Luego juega al golf con los modismos. Por ejemplo:

    ((((1↑⍴X),⍴Y)↑X)^.=Y)⌿X
    

    se puede transformar mecánicamente en:

    X⌿⍨Y^.=⍨X↑⍨(1↑⍴X),⍴Y
    

    y luego más en:

    X⌿⍨Y^.=⍨X↑⍨(⊃⍴X),⍴Y
    

    (primero) ser equivalente a 1↑(tomar uno) en este caso. Y posiblemente:

    X⌿⍨Y^.=⍨X↑⍨(≢X),⍴Y
    

    (tally) es equivalente a ⊃⍴(el primer elemento de la forma) para todos menos los escalares.

marinus
fuente
¿Hay alguna manera de obtener una licencia gratuita además de tener la versión raspberry pi?
Fabinout
Una forma legal de obtenerlo, obviamente.
Fabinout
2
@Fabinout: en dyalog.com puede descargar una versión gratuita de Windows. Haga clic en "Zona de descarga" y luego en "Descarga no registrada". Te molestará que te registres, pero de lo contrario es completamente funcional, gratuito y legal. Si eres estudiante, puedes obtener la versión normal de forma gratuita completando un formulario. Si no vives en un país donde arruinan tu vida por piratear, bueno, ya sabes qué hacer.
marinus
También está Nars2000, una implementación de código abierto que tiene muchas más funciones que Dyalog (y algunos errores). Algunas de sus características son útiles para jugar al golf, como las funciones de números primos o multisets.
Tobia
1
Hay GNU APL.
M. Alaggan
14

Trenes

A(f g h)B      ←→  (A f B)g A h B  ⍝ fork
 (f g h)B      ←→  (  f B)g   h B  ⍝ fork
A(  g h)B      ←→         g A h B  ⍝ atop
 (  g h)B      ←→         g   h B  ⍝ atop
 (A g h)       ←→  ({A} g h)       ⍝ "Agh" fork
 (f g h k)     ←→  (f (g h k))     ⍝ 4-train
 (f g h k l)   ←→  (f g (h k l))   ⍝ 5-train, etc
 (f g h k l m) ←→  (f(g h(k l m))) ⍝ groups of 3 from the right, last could be 2
  f∘g B        ←→    f g B         ⍝ "compose" operator, useful in trains
A f∘g B        ←→  A f g B
ngn
fuente
¿Eso significa que, por el bien de los futuros lectores, no deberíamos decirle a Oberon cómo acortarlo?
Adám
No, haz lo que normalmente harías en PPCG. Eliminaré esa línea después de que la expresión alcance (lo que creo que es) es la más corta. Es un ejercicio fácil, no creo que personalmente se beneficie de él.
ngn
Puedo reducirlo a 16, pero no estoy usando ninguno de tus consejos, así que tal vez estoy muy lejos.
Adám
@ Adám bueno, estás usando un tren :) el mío era similar pero más largo porque no pensé en ⎕ML
ngn
¿No es "grupos de 3 de la derecha "?
Adám
7

Trucos para tratar /y en trenes

Al usar trenes, es posible que desee usar reducciones f/como la suma +/o incluso replicar la reducción //. Sin embargo, si su tren tiene más partes a la izquierda de la reducción, necesita paréntesis para crear una cima. Aquí hay algunos trucos para guardar bytes.

Usar en 1∊lugar de matrices monádicas ∨/o ∨⌿booleanas

Tarea: Dadas dos cadenas de igual longitud A y B, devuelve 2 si alguno de los caracteres correspondientes de A y B son iguales, 0 de lo contrario. Por ejemplo, A←'abc'y B←'def'da 0y A←'abc'y B←'dec'da 2.

Puede ser una solución dfn A{2×∨/⍺=⍵}Bpero desea acortarla tácitamente. A(2×∨/=)Bno va a funcionar porque las reglas de formación de trenes analizan esto como 2 (× ∨/ =)quieres 2 × (∨/=).

Observe que ∨/o ∨⌿en un vector booleano ( ∨/,o ∨⌿,para matrices de rango superior) pregunta si hay 1 presente, es decir 1∊, para que podamos escribir nuestro tren como 2×1∊=.

Tenga en cuenta que descifra su argumento correcto, por lo que no puede usarlo para reducir cada fila o columna por separado.

Usar en 1⊥lugar de monádico +/o+⌿

Tarea: Dada una lista de listas L y un índice N, devuelve tres veces la suma de la enésima lista. Por ejemplo L←(3 1 4)(2 7)y N←1da 24.

Puede ser una solución dfn N{3×+/⍺⊃⍵}Lpero desea acortarla tácitamente. N(3×+/⊃)Lno va a funcionar porque las reglas de formación de trenes analizan esto como 3(× +/ ⊃)quieres 3 × (+/⊃).

Observe que evaluar una lista de números en unario (base-1) es equivalente a sumar la lista porque ∑ { a , b , c , d } =  a + b + c + d  = ( a × 1³) + ( b × 1² ) + ( c × 1¹) + ( d × 1⁰). Por +/a b c dlo tanto, es lo mismo que 1⊥a b c d, y podemos escribir nuestro tren como 3×1⊥⊃.

Tenga en cuenta que en argumentos de rango superior, 1⊥es equivalente a +⌿.

Usar en f.glugar de f/gcon argumentos escalares y / o vectoriales

Tarea: Dada una lista L y un número N, devuelve el rango 1 a través del número de división mínima restante cuando los elementos de L se dividen por NEg L←31 41 59y N←7da 1 2 3.

Puede ser una solución dfn N{⍳⌊/⍺|⍵}Lpero desea acortarla tácitamente. N(⍳⌊/|)Lno va a funcionar porque las reglas de formación de trenes analizan esto como ⍳ (⌊/) |quieres ⍳ (⌊/|).

El producto interno A f.g Bde dos funciones escalares cuando los argumentos son escalares y / o vectores es el mismo que f/ A g Bporque ambos son (A[1] g B[1]) f (A[2] g B[2]) f (A[3] g B[3])etc., por lo que podemos escribir nuestro tren como ⍳⌊.|.

Tenga en cuenta que esto no funciona para matrices de rango superior.

Use en ∊⊆lugar de /con argumentos booleanos izquierdo y simple vector derecho

Tarea: Dada una lista L y un número N, filtre la lista para que solo queden números mayores que N. Por ejemplo L←3 1 4y N←1da 3 4.

Puede ser una solución dfn N{(⍺<⍵)/⍵}Lpero desea acortarla tácitamente. N(</⊢)Lno funcionará porque las reglas de enlace analizarán esto como (</) ⊢pero desea /que la función se replique en lugar de que el operador reduzca .

Dyadic con un argumento izquierdo booleano divide el argumento derecho de acuerdo con corridas de 1s en el argumento izquierdo, dejando caer elementos indicados por 0s. Esto es casi lo que queremos, salvo la partición no deseada. Sin embargo, podemos deshacernos de la partición aplicando monadic . Así {(⍺<⍵)/⍵}puede convertirse {∊(⍺<⍵)⊆⍵}y así podemos escribir nuestro tren como ∊<⊆⊢.

Tenga en cuenta que esto no funciona para matrices de rango superior.

Usar en 0⊥lugar de ⊢/o ⊢⌿con argumentos numéricos

Tarea: Dada una lista L y un número N, multiplique el N con el elemento más a la derecha de LEg L←3 1 4y N←2da 8.

Puede ser una solución dfn N{⍺×⊢/⍵}Lpero desea acortarla tácitamente. N(⊣×⊢/⊢)Lno va a funcionar porque las reglas de formación de trenes analizan esto como ⊣ (× ⊢/ ⊢)quieres ⊣ × (⊢/⊢).

Observe que 0⊥en una matriz numérica es lo mismo que ⊢⌿, por lo que podemos escribir nuestro tren como ⊣×0⊥⊢.

Tenga en cuenta que esto selecciona la última celda principal de las matrices de rango superior.

Adán
fuente
1
¿Quizás podrías agregar esta respuesta de chat a esta?
J. Sallé
1
@ J.Sallé agregado.
Adám
7

Se usa para combinar multiplicación con suma

(a×b)+C  ->  a⊥b,C
(C)+a×b  ->  a⊥b,C
(a×b)-C  ->  a⊥b,-C

Suposiciones

  • ay bson términos que no requieren más paréntesis cuando se usan como argumento izquierdo

  • C es una expresión que puede necesitar paréntesis cuando se usa como argumento izquierdo

  • a b C evaluar a escalares numéricos

ngn
fuente
5

Números complejos

A menudo pasados ​​por alto, presentan oportunidades maravillosas para acortar expresiones relacionadas con cuadrículas, laberintos, fractales o geometría.

0j1⊥¨    0j1⊥   ⍝ pair(s) of reals -> complex
11 9∘○¨  11 9○  ⍝ complex -> pair(s) of reals
|z0-z1          ⍝ distance between two points
0j1×z   0j¯1×z  ⍝ rotate by ±90° around (0,0)
0j1*⍳4          ⍝ the four cardinal directions
+z       -+z    ⍝ reflect across x or y axis
+\0,z           ⍝ sequence of steps -> path
2-/z            ⍝ path -> sequence of steps
0j1⊥¨n-⍳2⍴1+2×n ⍝ lattice centred on (0,0)
ngn
fuente
4

Longitud del vector del módulo de indexación

⊃i⌽aa menudo es más corto que el ingenuo ⊃a[(≢a)|i]o a⊃⍨i|⍨≢a(donde aes un vector y ies un entero, y ⎕ioes 0)

Una variación útil de esto (gracias EriktheOutgolfer por señalar) es: I↑Y⌽⍨I×Xdónde Yestá la concatenación de algunos Ivectores de longitud y Xes el índice del que queremos elegir, por ejemplo:3↑'JanFeb...Dec'⌽⍨3×month

ngn
fuente
3

Funciones constantes

=⍨y ≠⍨gracias a ngn.

A veces solo necesita un valor único para cada elemento de una lista. Si bien puede tener la tentación de usarlo {value}¨, es más corto de usar, value⊣¨ pero para algunos valores comunes, puede ser aún más corto (usar ⎕IO←0):

¯1s con ⍬⍸list

0s con ⍬⍳list

1s con ⍬⍷list

Tenga en cuenta que estos solo funcionan en listas (aunque pueden estar anidados). Para las matrices de rango superior, puede usar lo siguiente para obtener todos los 0 y todos los 1:

1s con =⍨

0s con ≠⍨

Si establece ⎕ML←0, todos los números se pueden convertir en ceros (como si ) con:

Si solo necesita un solo número, puede usar monadic para obtener 1 o 0 en lugar de usar 1⊣o 0⊣.

Adán
fuente
" A veces sólo se necesita un único valor para cada elemento de una lista. " - Puede ser digno de mención: cuando ese valor es el primer elemento de la lista, puede utilizar⊣\
NGN
@ngn Yo diría eso y con /y merecen una publicación propia.
Adám
2

Utilizar

Evitar paréntesis

(Conmutar) puede ahorrarle bytes al evitar los paréntesis. Siempre que tenga una función en la que el argumento izquierdo necesite estar entre paréntesis y el argumento derecho no, puede guardar un byte, por ejemplo, (A<B)÷CC÷⍨A<B.

Matrices dobles

Para agregar una copia de una matriz a su fin, use ,⍨Ao ⍪⍨A.

Números dobles

En lugar de usar 2∘×para doblar, puede usarlo +⍨ya que agrega el argumento a sí mismo: 1+2∘×1++⍨.

Números cuadrados

En lugar de usar 2*⍨Yun cuadrado, puede usarlo ×⍨Yya que multiplica el argumento consigo mismo: 2*⍨A+B×⍨A+B.

Permutación aleatoria

?⍨Nte dará una permutación aleatoria de longitud N.

Autoclasificar

Encuentre los índices de la primera aparición de cada celda principal con ⍳⍨A

Cuente los 1s finales en un vector booleano

En lugar de +/∧\⌽Bcontar la cantidad de 1s finales Nque puede usar ⊥⍨.

Composición inversa

A f∘g Bes A f g B, pero si quieres (g A) f B, úsalo f⍨∘g⍨.

Reducción inversa

f/ a1 a2 a3es a1 f (a2 f a3). Si quieres (a1 f a2) f a3, úsalo f⍨/⌽.

Exploración inversa

f\ A B Ces
A (A f B) (A f (B f C)).

f⍨/∘⌽¨,\ A B Ces
A (A f B) ((A f B) f C).

f⍨\⌽ A B Ces
((A f B) f C) (B f C) C.

⌽f/∘⌽¨,\⌽ A B C. es
(A f (B f C)) (B f C) C.

Adán
fuente
2

Enumerar los caracteres en una cadena sin ⍳≢

Tarea: Dadas dos cadenas, S y T, enumere los índices de su concatenación. Por ejemplo S←'abcd'y T←'xyz'da 1 2 3 4 5 6 7.

Puede ser una solución dfn S{⍳≢⍺,⍵}Tpero desea acortarla tácitamente. ⍳≢,no va a funcionar porque las reglas de análisis del tren analizarán esto como (⍳)≢(,)quieras (⍳≢),.

Dyadic con un argumento izquierdo vacío califica las matrices de caracteres simples de acuerdo con su orden actual, que es el mismo que ⍳≢. Así {⍳≢⍺,⍵} puede convertirse {⍬⍋⍺,⍵}, así podemos escribir nuestro tren como ⍬⍋,.

Tenga en cuenta que esto no funciona para matrices numéricas o mixtas.

Adán
fuente
Wow, no sabía que era una cosa.
Zacharý