Поради щодо гольфу в APL


28

Нещодавно я розпочав один виклик для гольфу з кодом, і, здається, переможець - GolfScript (сюрприз, сюрприз!). Цікаво, що був ще один дуже сильний конкурент, який мав усі шанси перемогти GolfScript. Його назва - APL. Я бачу тут багато відповідей, написаних в APL. Здається, ця мова є досить ефективною для гольфу з кодами, тому я вирішу запитати будь-які поради щодо гольфу з кодом, які ви знаєте для програм APL. Сміливо розміщуйте кілька прикладів коду. Зазвичай дуже цікаво бачити мову в дії.

Відповіді:


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. Як і С, може поєднуватися з функцією, тобто 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діадичний, монадик застосовує один і той же аргумент до обох сторін функції:

            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
    

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


Чи є спосіб отримати безкоштовну ліцензію, окрім наявності версії малинового пі?
Fabinout

Очевидно, законний спосіб отримати його.
Fabinout

2
@Fabinout: На dyalog.com ви можете завантажити безкоштовну версію Windows. Клацніть «Завантажити зону», а потім «Незареєстроване завантаження». Це дозволить вам зареєструватися, але в іншому випадку це повністю функціонально, вільно та законно. Якщо ви студент, ви можете отримати звичайну версію безкоштовно, заповнивши форму. Якщо ви не живете в країні, де вони руйнують ваше життя за піратство, ну, ви знаєте, що робити.
marinus

Є також Nars2000, реалізація з відкритим кодом, яка має набагато більше можливостей, ніж Dyalog (і деякі помилки.) Деякі її функції корисні для гольфу, наприклад, функції простих чисел або мультисетів.
Тобія

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. Я видалю цей рядок після того, як вираз досягне (що я вважаю) його найкоротшого. Це легка вправа - я не думаю, що ви особисто отримаєте від цього користь.
ngn

Я можу це знизити до 16, але я не використовую жодних ваших порад, тому, можливо, я відволікаюся.
Adám

@ Adám добре, ти використовуєш потяг :) моя була схожа, але довша, тому що я не думав про ⎕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∊=.

Зауважте, що ravels правильний аргумент, тому ви не можете використовувати його для зменшення кожного рядка або стовпця окремо.

Використовуйте 1⊥замість монадних +/або+⌿

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

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

Зауважте, що оцінка списку чисел унарних (база-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не працює, тому що правила прив'язки будуть розбирати це як, (</) ⊢але ви хочете /бути копією функції, а не оператором зменшити .

Діадик з бульним лівим аргументом розділяє правий аргумент відповідно до пробігів 1s у лівому аргументі, відкидаючи елементи, зазначені 0s. Це майже те, що ми хочемо, окрім небажаного перегородки. Однак ми можемо позбутися від перегородки, застосувавши монадик . Таким чином ми {(⍺<⍵)/⍵}можемо стати, {∊(⍺<⍵)⊆⍵}і таким чином ми можемо написати наш поїзд як ∊<⊆⊢.

Зауважте, що це не працює для масивів вищого рангу.

Використовуйте 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ціле число, і ⎕ioдорівнює 0)

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


3

Постійні функції

=⍨і ≠⍨завдяки ngn.

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

¯1с с ⍬⍸list

0с с ⍬⍳list

1с с ⍬⍷list

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

1с с =⍨

0с с ≠⍨

Якщо встановлено ⎕ML←0, усі числа можна перетворити в нулі (як би ) за допомогою:

Якщо вам потрібен лише один номер, ви можете використовувати монадік, щоб отримати 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.

Самокласифікувати

Знайдіть показники першого виникнення кожної основної комірки з ⍳⍨A

Порахуйте кінцеві знаки в булевому векторі

Замість того, +/∧\⌽Bщоб підраховувати, скільки трейлінгів у 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але ви хочете скоротити його, мовчазно. ⍳≢,не буде працювати, тому що правила розбору поїздів розберуть це як слід, (⍳)≢(,)але ви хочете (⍳≢),.

Діадик із порожнім лівим аргументом класифікує прості масиви символів відповідно до їх поточного порядку, який такий самий, як ⍳≢. Таким чином {⍳≢⍺,⍵} може стати {⍬⍋⍺,⍵}, тому ми можемо написати свій поїзд як ⍬⍋,.

Зауважте, що це не працює для числових чи змішаних масивів.


Нічого собі, не знав, що це річ.
Zacharý
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.