Чи існує спосіб скорочення функцій жирової стрілки?


15

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

  1. Прості, які здатні виконувати як одне твердження, так і повертати відповідь, прямо з бати, як x=(a,b)=>a*a+b

  2. Більш складні, які зазвичай мають фігурні дужки через використання циклів, і як результат вимагають використання returnоператора ..p=b=>{m=b;for(a=1;~-m;)--m,a*=m*m;return a%b}

Беручи вищенаведений приклад із категорії 2 із концепцією фігурних брекетів як доказової концепції ... Чи існував би спосіб повторного гольфу цього коду (чи подібного), як цей, щоб усунути фігурні дужки, а також return? Я запитую лише це, оскільки це може потенційно (не кажучи, що це буде постійно) усунути 8 байт з коду гольфіста JS. Чи існують методи, які можна було б використовувати в цьому випадку? Я спробував рекурсію, але це m=bтвердження виявилося трохи помилкою, тому що я не можу це похитнути.

Щодо вищенаведеного коду, як би подати гольф, щоб усунути returnтвердження, незалежно від того, чи це гольфи коротше чи ні?

Відповіді:


18

Використовуйте рекурсію

Я виявив, що рекурсія (майже) завжди коротша за eval+ for. Загальний спосіб перетворення з for в eval:

for(a=n;b;c);d
(f=a=>b?f(c):d)(n)

Тож давайте подивимось на ваш приклад:

b=>{m=b;for(a=1;~-m;)--m,a*=m*m;return a%b}

Спочатку ми можемо спростити це до:

for(m=b,a=1;~-m;--m,a*=m*m)a%b;

Що ми тут зробили? Ну, ми просто перемістили все, що forописується, і це допомагає нам зменшити кількість крапки з комою, що не є безпосередньо кращим, але майже завжди призводить до гольфу.


Давайте поставимо це в eval і порівняємо його з версією рекурсії:

b=>{m=b;for(a=1;~-m;)--m,a*=m*m;return a%b}
b=>eval('for(m=b,a=1;~-m;--m,a*=m*m)a%b')
b=>(f=a=>~-m?(--m,f(a*=m*m)):a%b)(1,m=b)

У першій частині циклу for ( a=n) ми можемо розпочати це, передаючи ці змінні в якості аргументів. Умова проста: b?(c,f(a)):dде dповертається значення. Зазвичай cпросто змінюється, aщоб його можна було об’єднати. Тож ми можемо пограти ще більше, використовуючи те, що я згадав:

b=>(f=a=>~-m?(--m,f(a*=m*m)):a%b)(1,m=b)
b=>(f=a=>~-m?f(a*=--m*m):a%b)(1,m=b) // --m moved into a*=
b=>(f=a=>--m?f(a*=m*m):a%b)(1,m=b) // --m moved to condition

Це, як зазначає @Niel, спрощує ваш алгоритм. Алгоритм golfy на одній мові може не бути golfy на іншій, тому обов'язково спробуйте різні алгоритми та порівняйте їх.


1
Ви пропустили велику економію у спрощенні вихідного коду. ~-mє m-1, тому цикл може бути, for(m=b,a=1;--m;a*=m*m)a%b;і рекурсивна версія може бути (неперевірена)b=>(f=a=>--m?f(a*=m*m):a%b)(1,m=b)
Пітер Тейлор

1
Іноді потрібно просто використовувати інший алгоритм, але в цьому випадку найкраще, що я міг зробити, - це така ж довжина, як відповідь @ PeterTaylor:b=>b>1&(f=a=>--a<2||b%a&&f(a))(b)
Ніл

11

Зловживання eval.

Це просто. Замість:

f=n=>{for(i=c=0;i<n;i++)c+=n;return c}

Використовуйте

f=n=>eval("for(i=c=0;i<n;i++)c+=n;c")

Eval повертає останнє оцінене твердження. У цьому випадку, оскільки останнє оцінене твердження було б c+=n, у нас залишиться cвсе одно, заощадивши два байти.

f=n=>eval("for(i=c=0;i<n;i++)c+=n")

В загальному:

f=n=>eval("code;x")

коротше цього, байтом:

f=n=>{code;return x}

Як зауваження, використання могил для виклику eval для можливого збереження байтів не працює, оскільки:

eval`string`

еквівалентно

["string"]

Корисно для затухання! Не стільки для кодового гольфу.


2
foo`string`завжди еквівалентно foo(["string"]), просто багато функцій потім повертають масив до потрібного рядка.
Ніл

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