Czy istnieje sposób na skrócenie funkcji strzałek tłuszczu?

15

Z tego, co widziałem przez cały czas tutaj na PPCG, większość wpisów JavaScript dotyczących funkcji grubych strzałek jest zwykle jednym z dwóch obozów:

  1. Proste, które mogą działać jako pojedyncze zdanie i zwracać odpowiedź od razu, jak nietoperz x=(a,b)=>a*a+b

  2. Bardziej złożone, które zwykle mają nawiasy klamrowe z powodu użycia pętli, w związku z czym wymagają użycia returninstrukcji.p=b=>{m=b;for(a=1;~-m;)--m,a*=m*m;return a%b}

Biorąc powyższy przykład z kategorii 2 z koncepcją nawiasów klamrowych jako proof-of-concept ... Czy istnieje sposób na ponowne golfowanie tego kodu (lub podobnego) w taki sposób, aby wyeliminować nawiasy klamrowe, a także return? Pytam tylko o to, ponieważ może to potencjalnie (nie powiedzieć, że tak się stanie przez cały czas) wyeliminować 8 bajtów z kodu golfisty JS. Czy są jakieś techniki, które można zastosować w tym przypadku? Próbowałem rekurencji, ale to m=bstwierdzenie okazało się trochę mylące, ponieważ nie mogę tego potrząsnąć.

W przypadku powyższego kodu, w jaki sposób jeden golf mógłby to dodatkowo wyeliminować return, niezależnie od tego, czy gra w golfa krócej, czy nie?

WallyWest
źródło

Odpowiedzi:

18

Użyj rekurencji

Przekonałem się, że rekurencja jest (prawie) zawsze krótsza niż eval+ for. Ogólny sposób konwersji z for na eval to:

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

Zobaczmy więc twój przykład:

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

Możemy to najpierw uprościć, aby:

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

Co my tu zrobiliśmy? Po prostu przenieśliśmy wszystko do forinstrukcji, co pomaga nam zmniejszyć liczbę średników, co nie jest bezpośrednio lepsze, ale prawie zawsze prowadzi do golfa.


Umieśćmy to w eval i porównajmy z wersją rekurencyjną:

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)

Pierwszą część funkcji for loop ( a=n) możemy rozpocząć od przekazania tych zmiennych jako argumentów. Warunek jest po prostu: b?(c,f(a)):dgdzie djest zwracana wartość. Zwykle cpo prostu modyfikuje, aaby można go było scalić. Abyśmy mogli grać w golfa jeszcze bardziej, korzystając z tego, co wspomniałem:

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

To powiedziawszy, jak zauważył @Niel, upraszcza twój algorytm. Algorytm golfy w jednym języku może nie być golfy w innym, więc wypróbuj różne algorytmy i porównaj je.

Downgoat
źródło
1
Brakowało dużej oszczędności w uproszczeniu oryginalnego kodu. ~-mjest m-1, więc pętla może być, for(m=b,a=1;--m;a*=m*m)a%b;a wersja rekurencyjna może być (niesprawdzona)b=>(f=a=>--m?f(a*=m*m):a%b)(1,m=b)
Peter Taylor
1
Czasami musisz po prostu użyć innego algorytmu, ale w tym przypadku najlepszą rzeczą, jaką mogłem zrobić, była ta sama długość, co odpowiedź @ PeterTaylor:b=>b>1&(f=a=>--a<2||b%a&&f(a))(b)
Neil
11

Ewolucja nadużyć.

To proste. Zamiast:

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

Posługiwać się

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

Eval zwraca ostatnią ocenianą instrukcję. W tym przypadku, ponieważ ostatnia oceniana instrukcja byłaby c+=n, zostalibyśmy z tym c, oszczędzając dwa bajty.

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

Ogólnie:

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

jest krótszy niż bajt:

f=n=>{code;return x}

Uwaga: używanie grobów do wywołania eval w celu zapisania bajtów nie działa, ponieważ:

eval`string`

jest równa

["string"]

Pomocny w zaciemnieniu! Nie tyle w golfa kodu.

Conor O'Brien
źródło
2
foo`string`jest zawsze równoważne foo(["string"]), tyle że wiele funkcji rzutuje tablicę z powrotem na pożądany ciąg.
Neil,
@Neil Oh, jakie ciekawe!
Conor O'Brien