Советы по игре в гольф в APL

28

Я недавно запустил один тестовый гольф, и кажется, что победителем стал GolfScript (сюрприз, сюрприз!). Интересно то, что был еще один очень сильный конкурент, у которого были все шансы победить GolfScript. Его зовут APL. Я вижу много ответов, написанных в APL здесь. Похоже, что этот язык достаточно эффективен для игры в гольф кода, поэтому я решаю попросить любые советы по игре в гольф кода, которые вы знаете для программ APL. Не стесняйтесь размещать некоторые примеры кода. Обычно очень интересно видеть язык в действии.

gthacoder
источник

Ответы:

23

Редактировать : для тех, кто читает это, кто совсем не знает APL, но хочет его изучать , Mastering Dyalog APL - очень хороший ресурс.

  1. Оценка строго справа налево. Это включает в себя настройку переменных, так что воспользуйтесь этим.

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

    aустановлен в 1, 1+aоценивает 2, a,2оценивает 1 2и 2+1 2оценивает 3 4.

  2. Как C, могут быть объединены с функцией, то есть a +← 3. В отличие от C, это универсально: foo F← barустанавливает fooв F bar. Несколько неинтуитивно, как выражение это возвращается bar, а не F bar.

    Он также работает с анонимными функциями:

          a←0
          a+←3 ⋄ a
    3
          a+←3 ⋄ a
    6
          a { ⍵/'!' } ←4 ⋄ a
    !!!!
    
  3. Вы можете назначить массиву A[3]←8, как вы ожидаете. Но вы также можете назначить несколько элементов одновременно: A[3 5 6]←9 1 4или даже A[3 5 6]←9установить их для одного и того же элемента. Вы, конечно, можете добавить функцию здесь. Затем функция будет применена к каждому элементу отдельно, как если бы вы это сделали .

  4. твой друг, даже если он не выглядит слишком счастливым по этому поводу.

    1. Если Fэто диадическое, диадическое переключает аргументы: a F b<-> b F⍨ a. Это удобно при игре в гольф, потому что это может спасти вас от использования брекетов:

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

      Это меняет порядок оценки, поскольку правая рука всегда оценивается раньше левой.

    2. Если Fэто двоичное, то monadic применяет один и тот же аргумент к обеим сторонам функции:

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

      Аргумент оценивается только один раз. Это особенно полезно для внешних продуктов, т. Е. Для сравнения каждого значения в массиве с другими значениями в том же массиве вы можете использовать ∘.=⍨вместо необходимости x∘.=x←(whatever).

    3. Если Fявляется монадическим, ничего не делает, но отделяет функцию от аргумента. Таким образом, он может сохранить ваши скобки, если функция сложная:

            {⍵+3}⍣5 6
            ∇{⍵+3}              
           ∇ ⍣ 5 6              
            ({⍵+3}⍣5)6
      21
            {⍵+3}⍣5⍨6
      21
      
  5. Изучите идиомы! Тогда играйте в гольф идиомы. Например:

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

    может быть механически преобразован в:

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

    а затем далее в:

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

    (первый) эквивалентен 1↑(взять один) в этом случае. И возможно:

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

    (подсчет) эквивалентен ⊃⍴(первый элемент фигуры) для всех, кроме скаляров.

Мэринус
источник
Есть ли способ получить бесплатную лицензию, кроме версии Raspberry Pi?
Fabinout
Легальный способ получить это, очевидно.
Fabinout
2
@Fabinout: на dyalog.com вы можете скачать бесплатную версию для Windows. Нажмите «Зона загрузки», а затем «Незарегистрированная загрузка». Это заставит вас зарегистрироваться, но в остальном он полностью функционален, бесплатен и легален. Если вы студент, вы можете получить нормальную версию бесплатно, заполнив форму. Если вы не живете в стране, где они разрушают вашу жизнь за пиратство, вы знаете, что делать.
Маринус
Существует также Nars2000, реализация с открытым исходным кодом, которая имеет гораздо больше функций, чем Dyalog (и некоторые ошибки). Некоторые из ее функций пригодятся для игры в гольф, такие как функции простых чисел или мультимножества.
Tobia
1
Есть GNU APL.
М. Алагган,
14

Поезда

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
СПП
источник
Значит ли это, что ради будущих читателей мы не должны указывать Оберону, как его сократить?
Адам
Нет, делай как обычно на PPCG. Я уберу эту строку после того, как выражение достигнет (как мне кажется,) его кратчайшего. Это простое упражнение - я не думаю, что вы лично выиграете от этого.
нг
Я могу довести его до 16, но я не использую ни одного из ваших советов, так что, возможно, я далеко.
Адам
@ Ада, хорошо, ты ездишь на поезде :) мой был похож, но длиннее, потому что я не думал о ⎕ML
ngn
Разве это не «группы по 3 справа »?
Адам
7

Трюки для работы с поездами /и в поездах

При использовании поездов вы можете использовать сокращения, f/такие как сумма +/или даже дублирование сокращения //. Однако, если ваш поезд имеет больше частей слева от сокращения, вам нужно заключить в скобки верхнюю часть. Вот несколько приемов для сохранения байтов.

Используйте 1∊вместо монадических ∨/или ∨⌿логических массивов

Задача: Если заданы две строки A и B одинаковой длины, вернуть 2, если любые соответствующие символы A и B равны, иначе 0. Например , A←'abc'и B←'def'дает 0и A←'abc'и B←'dec'дает 2.

Решение dfn может быть, A{2×∨/⍺=⍵}Bно вы хотите сократить его, перейдя в молчание. A(2×∨/=)Bне собирается работать, потому что правила формирования поезда разбирают это так, как 2 (× ∨/ =)вы хотите 2 × (∨/=).

Заметим, что ∨/или ∨⌿на булевом векторе ( ∨/,или ∨⌿,для массивов более высокого ранга) спрашивается, есть ли 1, то есть 1∊мы можем записать наш поезд как 2×1∊=.

Обратите внимание, что это правильный аргумент, поэтому вы не можете использовать его для уменьшения каждой строки или столбца в отдельности.

Используйте 1⊥вместо монадического +/или+⌿

Задача: учитывая список списков L и индекс N, вернуть трижды сумму N-го списка. Например L←(3 1 4)(2 7)и N←1дает 24.

Решение dfn может быть, N{3×+/⍺⊃⍵}Lно вы хотите сократить его, перейдя в молчание. N(3×+/⊃)Lне собирается работать, потому что правила формирования поезда разбирают это так, как 3(× +/ ⊃)вы хотите 3 × (+/⊃).

Заметьте, что вычисление списка чисел в унарном (base-1) эквивалентно суммированию списка, потому что ∑ { a , b , c , d } =  a + b + c + d  = ( a × 1³) + ( b × 1² ) + ( c × 1¹) + ( d × 1⁰). Поэтому так +/a b c dже, как 1⊥a b c dи мы можем написать наш поезд, как 3×1⊥⊃.

Обратите внимание, что для аргументов более высокого ранга 1⊥эквивалентно +⌿.

Использовать f.gвместо f/gскалярных и / или векторных аргументов

Задача: учитывая список L и число N, верните диапазон 1 до числа минимального остатка деления, когда элементы L делятся на NEg L←31 41 59и N←7дают 1 2 3.

Решение dfn может быть, N{⍳⌊/⍺|⍵}Lно вы хотите сократить его, перейдя в молчание. N(⍳⌊/|)Lне собирается работать, потому что правила формирования поезда разбирают это так, как ⍳ (⌊/) |вы хотите ⍳ (⌊/|).

Внутреннее произведение A f.g Bскалярных двух функций, когда аргументы являются скалярами и / или векторами, совпадает с тем, f/ A g Bчто оба они (A[1] g B[1]) f (A[2] g B[2]) f (A[3] g B[3])и т. Д., Поэтому мы можем записать наш поезд как ⍳⌊.|.

Обратите внимание, что это не работает для массивов более высокого ранга.

Используйте ∊⊆вместо /логических аргументов левый и простой векторный правый

Задача: учитывая список L и число N, отфильтруйте список так, чтобы остались только числа больше N. Например L←3 1 4и N←1дает 3 4.

Решение dfn может быть, N{(⍺<⍵)/⍵}Lно вы хотите сократить его, перейдя в молчание. N(</⊢)Lне будет работать, потому что правила привязки будут анализировать это как, (</) ⊢но вы хотите, /чтобы функция копировалась, а не уменьшала оператор .

Dyadic с логическим левым аргументом разбивает правый аргумент в соответствии с сериями 1 в левом аргументе, отбрасывая элементы, обозначенные 0. Это почти то, что мы хотим, за исключением нежелательных разделов. Тем не менее, мы можем избавиться от разбиения, применяя monadic . Таким образом {(⍺<⍵)/⍵}может стать {∊(⍺<⍵)⊆⍵}и таким образом мы можем написать наш поезд как ∊<⊆⊢.

Обратите внимание, что это не работает для массивов более высокого ранга.

Использовать 0⊥вместо ⊢/или ⊢⌿с числовыми аргументами

Задача: Учитывая список L и число N, Умножить N с правым элементом Ноги L←3 1 4и N←2дает 8.

Решение dfn может быть, N{⍺×⊢/⍵}Lно вы хотите сократить его, перейдя в молчание. N(⊣×⊢/⊢)Lне собирается работать, потому что правила формирования поезда разбирают это так, как ⊣ (× ⊢/ ⊢)вы хотите ⊣ × (⊢/⊢).

Заметьте, что 0⊥числовой массив такой же, как ⊢⌿, поэтому мы можем записать наш поезд как ⊣×0⊥⊢.

Обратите внимание, что это выбирает последнюю главную ячейку массивов более высокого ранга.

Адам
источник
1
Может быть, вы могли бы добавить этот чат ответ на этот?
Ж. Салле
1
@ J.Sallé Добавлено.
Адам
7

Используйте для объединения умножения с сложением

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

Предположения:

  • aи bявляются терминами, которые не требуют дополнительных скобок при использовании в качестве левого аргумента

  • C это выражение, которое может нуждаться в скобках при использовании в качестве левого аргумента

  • a b C оценивать по числовым скалярам

СПП
источник
5

Сложные числа

Часто упускаемые из виду, они предоставляют прекрасные возможности для сокращения выражений, связанных с сетками, лабиринтами, фракталами или геометрией.

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)
СПП
источник
4

Индексирование по модулю длины вектора

⊃i⌽aчасто короче наивного ⊃a[(≢a)|i]или a⊃⍨i|⍨≢a(где aвектор и iцелое число ⎕io0)

полезный вариант этого (спасибо EriktheOutgolfer за указание): I↑Y⌽⍨I×Xгде Y- конкатенация некоторых Iвекторов длины и Xиндекс того, который мы хотим выбрать, например:3↑'JanFeb...Dec'⌽⍨3×month

СПП
источник
3

Постоянные функции

=⍨и ≠⍨благодаря нгн.

Иногда вам просто нужно одно значение для каждого элемента списка. Хотя у вас может возникнуть соблазн использовать {value}¨его, он короче, value⊣¨ но для некоторых общих значений вы можете стать еще короче (используя ⎕IO←0):

¯1с ⍬⍸list

0с ⍬⍳list

1с ⍬⍷list

Обратите внимание, что они работают только со списками (хотя они могут быть вложенными). Для массивов более высокого ранга вы можете использовать следующее, чтобы получить все 0 и все 1:

1с =⍨

0с ≠⍨

Если вы установите ⎕ML←0, все числа могут быть превращены в нули (как будто ) с помощью:

Если вам нужен только один номер, вы можете использовать monadic для получения 1 или 0 вместо использования 1⊣или 0⊣.

Адам
источник
« Иногда вам просто нужно одно значение для каждого элемента списка». - Это может быть примечательно: если это значение является первым элементом списка, вы можете использовать⊣\
ngn
@ngn Я бы сказал , что и с /и достоинством должности своих собственным.
Адам
2

использование

Избегайте скобок

(Commute) может сохранить ваши байты, избегая скобок. Если у вас есть функция, в которой левый аргумент необходимо заключить в скобки, а правый - нет, вы можете сохранить байт, например (A<B)÷CC÷⍨A<B.

Двойные массивы

Чтобы добавить копию массива в его конец, используйте ,⍨Aили ⍪⍨A.

Двойные числа

Вместо использования 2∘×для удвоения, вы можете использовать, +⍨так как он добавляет аргумент к себе: 1+2∘×1++⍨.

Квадратные числа

Вместо использования 2*⍨Yв квадрат вы можете использовать, ×⍨Yтак как он умножает аргумент на себя: 2*⍨A+B×⍨A+B.

Случайная перестановка

?⍨Nдаст вам случайную перестановку длины N.

Self-Классифицировать

Найти индексы первого появления каждой крупной ячейки с ⍳⍨A

Подсчитайте конечные единицы в булевом векторе

Вместо того, +/∧\⌽Bчтобы посчитать, сколько трейлингов 1 Nможно использовать ⊥⍨.

Обратная композиция

A f∘g Bесть A f g B, но если хочешь (g A) f B, используй f⍨∘g⍨.

Обратное уменьшение

f/ a1 a2 a3есть a1 f (a2 f a3). Если хочешь (a1 f a2) f a3, используй f⍨/⌽.

Обратное сканирование

f\ A B Cесть
A (A f B) (A f (B f C)).

f⍨/∘⌽¨,\ A B Cесть
A (A f B) ((A f B) f C).

f⍨\⌽ A B Cесть
((A f B) f C) (B f C) C.

⌽f/∘⌽¨,\⌽ A B C, есть
(A f (B f C)) (B f C) C.

Адам
источник
2

Перечислять символы в строке без ⍳≢

Задача: Для двух строк, S и T, перечислить индексы их конкатенации. Например S←'abcd'и T←'xyz'дает 1 2 3 4 5 6 7.

Решение dfn может быть, S{⍳≢⍺,⍵}Tно вы хотите сократить его, перейдя в молчание. ⍳≢,не будет работать, потому что правила парсинга поезда будут анализировать это так, как (⍳)≢(,)вы хотите (⍳≢),.

Dyadic с пустым левым аргументом классифицирует простые символьные массивы в соответствии с их текущим порядком, который совпадает с ⍳≢. Таким образом {⍳≢⍺,⍵} может стать {⍬⍋⍺,⍵}, поэтому мы можем написать наш поезд как ⍬⍋,.

Обратите внимание, что это не работает для числовых или смешанных массивов.

Адам
источник
Вау, не знал, что это вещь.
Захари