Есть ли способ сократить функции жирной стрелки?


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 golfer. Есть ли какие-либо методы, которые можно использовать в этом случае? Я пробовал рекурсию, но 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, это упрощает ваш алгоритм. Алгоритм игры в гольф на одном языке не может быть игрой в гольф на другом языке, поэтому обязательно попробуйте разные алгоритмы и сравните их.


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)
Neil

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"]), просто многие функции затем приводят массив обратно к желаемой строке.
Нил

@ Нил О, как интересно!
Конор О'Брайен,
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.