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


17

K - мова програмування в родині APL, розроблена Артуром Вітні. Хоча офіційний перекладач є закритим і комерційним, пробну версію з обмеженням робочого простору на 32 біти простору адреси (що не повинно створювати проблем для коду гольфу) можна знайти на веб-сайті Kx Systems . Ця версія в комплекті з базою даних kdb + в розмовній формі називається "K4". Також доступні K-версії з відкритим кодом, зокрема Kona , що базується на K3, і мій власний інтерпретатор під назвою oK , який базується на K5 та має REPL на базі браузера .

Kx Systems має вікі з інформацією про K4 / kdb + / Q, а сторінка Kona GitHub також має чудову колекцію довідкових матеріалів. Я почав писати посібник для oK / k5, який може бути корисним посиланням.

Як і J, і APL, K - дуже стисна і потужна мова, і вона часто може добре показувати в коді гольфу. Будь ласка, поділіться порадами, підказками та ідіомами, які ви знайдете, і якщо ви ще не пробували K, перш ніж подумайте про те, щоб розкрутити його! Опублікуйте будь-яку пораду за відповідь, будь ласка!

Відповіді:


5

Виклик Діади

Якщо припустити, що у вас була діадична (2-аргументальна) функція f:

f: {x+2*y}

Ви зазвичай називатимете так:

f[3;47]

Ви можете зберегти символ, замість цього провівши в першому аргументі, а потім застосувавши отриману часткову функцію до другого аргументу шляхом супозиції:

f[3]47

Це ж природно працює і для індексації масивів:

  z: (12 17 98;90 91 92)
(12 17 98
 90 91 92)

  z[1;2]
92

  z[1]2
92

5

Друк нових рядків

Якщо у вашому виході повинен бути новий рядок, ви можете спокуситись зробити це:

`0:whatever,"\n"

Не варто . K2 (і, ймовірно, інші версії) має чітку функцію, де ви можете надрукувати список рядків:

  `0:("abc";"def")
abc
def

Отже, якщо вам потрібно додати новий рядок до виводу, просто зробіть:

`0:,whatever

3

Діапазони

Зазвичай, якщо ви хочете створити вектор послідовних чисел, які ви використовуєте !:

  !5
0 1 2 3 4

Якщо ви хочете створити діапазон, який починається з числа, відмінного від нуля, слід додати зміщення до отриманого вектора:

  10+!5
10 11 12 13 14

Існує кілька незвичайних підходів, які могли б краще працювати в конкретній ситуації. Наприклад, якщо ваша база та компенсація вже є членами списку, ви можете використовувати "де" двічі:

  &10 5
0 0 0 0 0 0 0 0 0 0 1 1 1 1 1
  &&10 5
10 11 12 13 14

Для повільно зростаючих послідовностей розгляньте поєднання "де" з "взяти":

  5#2
2 2 2 2 2
  &5#2
0 0 1 1 2 2 3 3 4 4

Якщо ви хочете створити діапазон кратних, ви можете помножити результат !або ви можете сканувати ( \) список копій розміру кроку:

  2*!5
0 2 4 6 8
  +\5#2
2 4 6 8 10

Якщо ви намагаєтеся уникати круглих дужок, перші краще, якщо довжина послідовності є змінною і розмір кроків фіксований, а другий - краще, якщо розмір кроку - це те, що має тенденцію змінюватися. Вибір потрібного варіанту може зберегти 1 або 2 символи. Різниця, що перебуває за одним, може також працювати на вашу користь.


2

Касти з струн дорого коштують. Просто використовуйте eval. Це:

0.0$a

може стати саме цим:

. a

У K5 - це байт коротше:

.a

2

Кожна справа

Іноді ви можете виявити, що ви пишете (або наштовхуєтесь на спрощення), викладений в дужках вираз, застосований через монаду:

  (2#)'3 4 5
(3 3
 4 4
 5 5)

Це на один символ коротше, щоб перетворити цей шаблон у додаток кожного праворуч:

  2#/:3 4 5
(3 3
 4 4
 5 5)

1

Циклічні перестановки

Діад !в K3 / K4 "повертається":

  2!"abcd"
"cdab"
  -1!"abcd"
"dabc"

Коли "scan" ( \) надається монадичним дієсловом, він виступає оператором з фіксованою точкою. У K оператори фіксованої точки неодноразово застосовують своє дієслово до значення, поки початкове значення не переглянеться або значення перестане змінюватися. Поєднання обертання із скануванням з фіксованою точкою забезпечує дуже зручний спосіб обчислення набору циклічних перестановок списку:

  ![1]\1 2 4 8
(1 2 4 8
 2 4 8 1
 4 8 1 2
 8 1 2 4)

!Для створення дієслівного поїзда ви можете викривити дужки або скобки (1!):

![1]\
(1!)\

(Зауважте, що 1!\ має зовсім іншу поведінку!) Кожна з них за рівнем рівнозначна, але перша може бути більш бажаною, якщо крок обертання є чимось іншим, ніж 1; у цьому випадку дужки обмежують дужки в дужках «безкоштовно».

Як приклад, ось коротка програма, яка перевіряє через грубу силу, чи містить рядок x підрядку y (циклічно!):

{|/(y~(#y)#)'![1]\x}

Користувачі K5 будьте обережні! K5 змінив значення діадичного !, тому ця методика не така проста. Він працюватиме так, як очікувалося в Коні.


1

Уникайте умовних умов

K має умовну конструкцію ( :[), яка еквівалентна стилю Ліспа cond:

:[cond1;result1; cond2;result2; cond3;result3; default]

Ви можете мати скільки завгодно умов, і якщо жодне не відповідає значенню за замовчуванням, не повертається.

Іноді (як у рекурсивних програмах чи програмах, які в іншому випадку покладаються на послідовність побічних ефектів), неможливо обійтись одним із них. Однак у ситуаціях, коли ви можете дозволити собі зробити додаткову роботу, часто можете замінити "cond" на індексацію списку.

Розгляньте сумнозвісну програму fizzbuzz . Написані у звичайному імперативному стилі програмування, ми можемо піти з:

{:[~x!15;"FizzBuzz";~x!3;"Fizz";~x!5;"Buzz";x]}'1+!100

Тут є досить багато повторень у тестах на роздільність. Інший підхід визнає, що є 4 випадки (кількість, поділ лише на 3, поділ лише на 5, поділ на 3 і 5) та спроби безпосередньо обчислити індекс, який обирає один із цих випадків зі списку:

{(x;"Fizz";"Buzz";"FizzBuzz")@+/1 2*~x!/:3 5}'1+!100

Два символи коротше, а мова краще використовується. Знаючи, що літерали списків оцінюються праворуч ліворуч, ми також отримуємо деякі додаткові можливості для гольфу для поєднання повторно використаних субпрекспресій. Ми не могли б легко зробити це у конвертованій версії, оскільки рядкові рядки взагалі не оцінюються, якщо вони не вибрані:

{(x;4#t;4_ t;t:"FizzBuzz")@+/1 2*~x!/:3 5}'1+!100

Тепер ми зберегли 5 символів. До речі, саме цей приклад працює в k5 ще приємніше, оскільки у нас є перевантаження "pack" для /обробки кроку множення на вектор коефіцієнтів та підсумовування:

{(x;4_t;4#t;t:"FizzBuzz")@2 2/~3 5!\:x}'1+!100

Також зауважте, що поведінка "find" ( ?), яка виробляє індекс минулого кінця списку ключів, якщо елемент не знайдений, спеціально розроблена для підтримки обробки випадку "за замовчуванням" у такому вигляді індексації. Розглянемо цей фрагмент для перетворення голосних звуків у великі регістри:

{("AEIOU",x)"aeiou"?x}'

У порівнянні з одним із:

{t:"aeiou"?x;:[t<5;"AEIOU"t;x]}'
{:[~4<t:"aeiou"?x;"AEIOU"t;x]}'

(Я знаю, що я теж хотів би прочитати!)

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