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


16

Які загальні поради щодо гольфу в Perl 6? Я шукаю ідеї, які можна застосувати до проблем із гольфом взагалі, які принаймні дещо специфічні для Perl 6 (наприклад, "видалити коментарі" - це не відповідь). Будь ласка, опублікуйте одну пораду на відповідь.

Зверніть увагу, що Perl 6 не є Perl 5, тому це питання не є дублікатом. Більшість порад щодо гольфу Perl 5 просто не стосуються Perl 6.

Відповіді:


9

Уникайте subлітералів. У багатьох випадках ви можете просто використовувати {}для блоків коду. Наприклад, не пишіть наступний код.

sub ($a){$a*2}

Замість цього використовуйте синтаксис блоків. Це також дозволяє використовувати $_, @_і %_шаблонні змінні, якщо вам потрібно тільки одну змінну. Якщо вам потрібно більше, ви можете використовувати $^a, $^bзмінні, і так далі.

{$_*2}

Крім того, у деяких рідкісних випадках можна використовувати будь-який код (особливо, коли у вас є прості вирази). Аргумент *заміщає заповнювач.

* *2

8

Perl 6 має дійсно химерну особливість, де вона дозволяє використовувати всі символи Unicode у категоріях Nd , Nl та  No як раціональні літеральні цифри. Деякі з них коротші, ніж записувати їх числові значення в ASCII:

  • ¼(2 байти) коротше .25або 1/4(3 байти).
  • ¾(2 байти) коротше .75або 3/4(3 байти).
  • (3 байти) коротше, ніж 1/16(4 байти).
  • 𐦼(4 байти) коротше, ніж 11/12(5 байт).
  • 𒐲(4 байти) коротше, ніж 216e3(5 байт).
  • 𒐳(4 байти) коротше, ніж 432e3(5 байт).

В якості подальшого контролю для цього ви також можете використовувати експоненти Unicode, навіть з кількома цифрами та / або мінусом: say (3² + 4², 2²⁰, 5⁻²)==> (25 1048576 0.04). Повний список Unicode, який ви можете зловживати таким чином, тут: docs.perl6.org/language/unicode_texas .
Раміллі

8

Вивчіть функції читання вводу. Perl 6 має безліч цікавих функцій, які легко зчитують вхід з ARGV або STDIN (якщо нічого не вказано в ARGV), що може скоротити ваш код при правильному використанні. Якщо ви називаєте їх методами файлових файлів, ви можете змусити їх працювати над певним файловим файлом (корисно, якщо ви, наприклад, читаєте STDIN, але вам доведеться читати аргументи на ARGV).

get

Ця функція отримує єдиний рядок і автоматично підключає її, тому не потрібно. Це корисно, якщо вам потрібно прочитати лише один рядок.

lines

Ця функція отримує всі рядки з файлу або STDIN. Це лінивий список, тому якщо ви його використовуєте for, він читатиме лише те, що вам потрібно. Наприклад.

say "<$_>"for lines

slurp

Це прочитає весь файл або STDIN і поверне результат у вигляді одного рядка.


Ця помилка була виправлена ​​- не знаю коли, але say "<$_>" for linesпрацює зараз
кіт

5

Попередження : наближається стіна тексту. Це дуже багато маленьких хитрощів, які я зібрав з часом.

Пишіть свої рішення як анонімні блоки

Про це вже згадувалося, але я хотів би ще раз зазначити це. У TIO ви можете записати my $f =в заголовок, блок в належний код і запустити колонтитул з а ;. Це здається далеко не самим коротким способом виконати роботу (оскільки вам не потрібно дбати про читання будь-яких матеріалів, вони вам даються в аргументах).

Ще одним приємним способом є використання перемикача -nабо -p, але я не знайшов способу змусити його працювати в TIO.

Використовуйте синтаксис двокрапки для передачі аргументів

Тобто замість цього thing.method(foo,bar)ви можете зробити thing.method:foo,barі зберегти 1 символ. На жаль, ви не можете викликати інший метод результату з зрозумілих причин, тому має сенс використовувати лише останній метод у блоці.

Використовуйте $_стільки, скільки можете

Іноді краще взяти аргумент із одного списку, ніж кілька окремих аргументів через це. Під час доступу$_ ви можете викликати методи на ньому, лише починаючи з крапки: наприклад .sort, дорівнює $_.sort.

Однак майте на увазі, що кожен блок отримує своє $_, тому параметри зовнішнього блоку не поширюватимуться на внутрішні. Якщо вам потрібно отримати доступ до параметрів основної функції з внутрішнього блоку, ...

Використовувати ^ змінні, якщо ви не можете їх використовувати$_

Вставте ^між сігіли і ім'ям змінним, як це: $^a. Вони працюють лише всередині блоку. Компілятор спочатку підраховує, скільки з них у вас в блоці, сортує їх лексикографічно, а потім присвоює перший аргумент першому, другий - другому тощо. Ці ^потреби , які будуть використовуватися тільки в першій згадці змінної. Так{$^a - $^b} бере 2 скаляри і віднімає їх. Єдине, що має значення - це алфавітний порядок, так {-$^b + $^a}само і те саме.

Якщо ви коли-небудь захочете використовувати синтаксис точкового блоку (подібний ->$a,$b {$a.map:{$_+$b}}), вам набагато краще писати помилкове твердження на початку блоку, використовуючи ^кожен аргумент, який ви не збираєтеся використовувати в основному блоці (наприклад {$^b;$^a.map:{$_+$b}}) (Примітка це кращий шлях до гольфу {$^a.map(*+$^b)}. Я просто хотів показати цю концепцію.)

Уважно прочитайте документи оператора

Оператори дуже потужні, і часто вони є найкоротшим способом впоратися. Особливо мета-оператори (оператори , які приймають оператори в якості аргументу) [], [\], X, <</ >>іZ варта вашої уваги. Не забувайте, що метаоператор може сприймати інший метаоператор як аргумент (наприклад, XZ%%мені вдалося використати тут ). Ви також можете використовувати >>для виклику методу, який може бути набагато дешевше, ніж карта ( @list>>.methodзамість @list.map(*.method), але будьте обережні, вони не однакові! ). І, нарешті, перед тим, як скористатись двійковим файлом << >>, пам’ятайте, що Zчасто буде робити те саме, що значно менше символів.

Якщо ви збираєте багато метаоперацій один на одного, ви можете вказати пріоритет за допомогою квадратних дужок []. Це допоможе вам заощадити, коли ви накопичите стільки операторів, що заплутають компілятор. (Це трапляється не дуже часто.)

Нарешті, якщо вам потрібно примусити речі до Bool, Int або Str, не використовуйте методи .Bool , .Intі .Str, а оператори ?, +і ~. Або ще краще, просто введіть їх в арифметичний вираз, щоб змусити їх у Int і так далі. Найкоротший спосіб отримати довжину списку +@list. Якщо ви хочете обчислити 2 до потужності довжини списку, просто скажіть, 2**@listі це зробить правильну річ.

Використовуйте вільні змінні стану $, @і%

У кожному блоці кожне виникнення $(або @або %) посилається на нову блискучу скалярну (або масив, або хеш) змінну стану (змінна, значення якої зберігається у викликах до блоку). Якщо вам потрібна змінна стан, на яку потрібно посилатися лише один раз у вихідному коді, ці троє - ваші великі друзі. (Найчастіше $.) Наприклад, у виклику Reverse Math Cycles це може бути використано для вибору операторів циклічно з масиву, який індексувався$++%6 .

Використовуйте підформи map,grep і ін.

Це означає: робити, а map {my block},listне робити list.map({my block}). Навіть якщо вам вдасться використовуватиlist.map:{my block} , ці два підходи виходять при однаковій кількості байтів. І часто вам потрібно скористатись дужкою списку під час виклику методу, але не під час виклику суб. Таким чином, підхід завжди виходить кращим або, принаймні, таким же, як і метод.

Єдиним винятком тут є те, коли знаходиться об'єкт, який має бути mapпед, grepпед тощо $_. Тоді .map:{}явно б’є map {},$_.

Використовуйте переходи ( &і| ) замість &&і ||.

Очевидно, вони на 1 байт коротші. З іншого боку, вони повинні бути згорнуті, будучи примушеними до булевого контексту. Це завжди можна зробити за допомогою a ?. Тут ви повинні знати про мета-оп!op яка змушує розкривати контекст, використовувати opі заперечувати результат.

Якщо у вас є список і ви хочете перетворити його на перехід, не використовуйте [&]і [|]. Замість використання .anyі .all. Існує також те, .noneщо не може так легко імітуватися перемикачем.


1
Я думаю, &&і ||все ще корисні для короткого замикання?
ASCII лише

@ ASCII-тільки: Так, звичайно, є.
Раміллі

4

Скоротіть простір, що використовується для змінних

До цього є кілька частин.

Видаліть пробіли

Змінні, задекларовані за допомогою, myзазвичай можуть бути оголошені без пробілу між myі назвою змінної. my @aеквівалентно my@a.

Використовуйте змінні без знаків

Ви можете оголосити змінні за допомогою зворотної косої риси для видалення sigil перед назвою змінної, наприклад:

my \a=1;

(на жаль, ви не можете видалити пробіл :()

Це корисно, оскільки ви згодом можете їх називати лише голою назвою змінної.

 a=5;
 a.say

В основному це економить байти, якщо ви використовуєте змінну більше ніж де-небудь в іншому місці коду. Мінусом є те, що змінну потрібно ініціалізувати.

Використовуйте $!і$/

Ці заздалегідь оголошені змінні зазвичай використовуються для виключень і збігів регулярних виразів, але їх не потрібно визначати, використовуючи my.

$!=1;
$/=5;

Особливо корисно використання $/в якості масиву та використання ярликів з $наступним номером для доступу до цього елемента $/масиву;

$/=100..200;
say $5;  #105
say $99; #199

2

Використовуйте ...замістьfirst

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

first &f,1..*

Однак замість цього ви можете використовувати ...оператора:

+(1...&f)

Якщо ви повинні почати з того 0, ви можете мати -1згодом замість цього +.

Якщо ви хочете, щоб індекс першого елемента в списку, @aякий має умову &f, зазвичай:

first &f,@a,:k

Замість цього:

(@a...&f)-1

(або навпаки, якщо потрібно 0 з індексом). Таким же чином ви можете отримати всі елементи до першого, який передає умову.

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

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