Twoja firma dopiero zaczyna projekt i po raz pierwszy zdecydowałaś się na funkcjonalny styl programowania. Jednak twój szef jest naprawdę nieufny i nie chce korzystać z wbudowanych funkcji, i wymaga od ciebie wdrożenia głównych funkcji. W szczególności trzeba napisać funkcje: Map
, Nest
, Apply
, Range
, Fold
i Table
w języku Twojego wyboru. Szef jest bardzo zajętym człowiekiem i chce, aby programy były jak najkrótsze, aby nie tracił czasu na czytanie. On również nie chce, abyś używał pętli, dlatego będziesz miał 10% zmniejszenie liczby bajtów za nieużywanie pętli.
Szczegółowe wymagania dotyczące funkcji są poniżej:
Mapa
Map
Funkcja przyjmuje dwa parametry: f
a list
gdzie f
jest funkcją i list
znajduje się lista wartości. Powinien zwrócić f
zastosowany do każdego elementu list
. Dlatego będzie działał jako taki:
Map(f,{a,b,c})
zwraca
{ f(a), f(b), f(c) }
i
Map(f, {{a,b},{b,c}})
zwraca
{ f({a,b}), f({b,c})}
Gniazdo
Nest
Funkcja przyjmuje trzy parametry, a także: f
, arg
, times
gdzie f
jest funkcją, arg
jest jej argument wyjściowy, i times
to ile razy funkcja jest stosowana. Powinien zwrócić wyrażenie z f
zastosowanymi times
czasami do arg
. Dlatego będzie działał jako taki:
Nest(f, x, 3)
zwraca
f(f(f(x)))
i
Nest(f, {a,b}, 3)
zwraca
f(f(f({a,b})))
Zastosować
Apply
Funkcja przyjmuje dwa parametry: f
a args
gdzie f
jest funkcją i args
lista. Powinien mieć zastosowanie f
do args
. W związku z tym:
Apply(f, {a,b,c})
zwraca
f(a,b,c)
Zasięg
Range
Funkcja ma jedną liczbą całkowitą r
i wysyła całkowitymi do tej liczby. W związku z tym:
Range(5)
zwraca
{ 1, 2, 3, 4, 5}
Zagięcie
Fold
Funkcja przyjmuje trzy parametry f
, arg
, others
gdzie f
jest funkcją, arg
jest prosty parametr, a others
lista. Będzie działał jako taki:
Fold(f, x, {a, b, c, d})
zwraca
f(f(f(f(x,a),b),c),d)
Stół
Funkcje tabel powinny przyjmować funkcję f
i parametr wywoływany iterator
w postaci: {iMin, iMax}
gdzie iMin
i iMax
są liczbami całkowitymi. Należy złożyć wniosek f
w określonym zakresie. W związku z tym:
Table(f, {0, 5})
zwraca
{f(0), f(1), f(2), f(3), f(4), f(5)}
Użyłem definicji tych funkcji ze strony programowania funkcjonalnego Mathematica , więc jeśli potrzebujesz więcej wskazówek, przejdź tam. Pamiętaj, że nie będziesz musiał implementować wszystkich wersji funkcji pokazanych na tej stronie, ale tylko te napisane w tym poście.
Standardowe luki są niedozwolone jak zwykle.
Jeśli twój język nie pozwala na przekazywanie funkcji jako argumentów, musisz zaimplementować tę możliwość i dodać ją do swojej odpowiedzi. Jednak liczba bajtów tej operacji nie zostanie dodana do sumy.
To jest kod golfowy, więc wygrywa najkrótszy kod. Powodzenia!!!
źródło
Table
tu działa. Czy twoim przykładem powinien byćTable(f, {x, 0, 5})
? Nie rozumiem też w ogóle celux
, ponieważ po prostu stosuje funkcję do zakresu.Odpowiedzi:
Haskell,
wiele poprzednich bajtów liczy127 * 0,9 = 114,3 bajtówŻadnych pętli, tylko rekurencja.
#
to mapa:(*2) # [1,2,3]
->[2,4,6]
&
jest gniazdem:((*2) & 3) 4
->48
i
stosuje się:i (*2) 7
->14
r
to zakres:r 4
->[1,2,3,4]
?
jest krotnie:((+) ? 0) [1,2,3,4]
->10
%
to tabela:(*2) % (2,4)
->[4,6,8]
Zgodnie z prośbą wersja bez golfa z komentarzami. Uwaga,
&
i?
są to trójskładnikowe operatory infix, które wymagają dodatkowych nawiasów, gdy są wywoływane lub pasują do wzorca.Podziękowania dla @dfeuer i @Zgarb za przydatne wskazówki
źródło
m#q=reverse$f((:).m)[]q
. Jest to ta sama długość co twoja, ale znacznie trudniejsza do odczytania.!
przez co zamiast nazwy operatora:i f=f
.Python 2, 305,1 bajtów (-10%
376369366349339 bajtów)Po rozwinięciu odpowiada:
Bez pętli!
Cóż, robi to dużo
eval
ingerencji, a jeśli twój szef nie wytrzyma pętli, NIENAWIDZI ewaluacji. Ale będą musieli to znieśćrange
Doceniany jest sposób działania w lambda, więc nie muszę wykonywać żadnych funkcji (wzdrygnąć się).Objaśnienia:
m=lambda f,l:eval("["+"f(l.pop()),"*len(l)+"][::-1]")
n=lambda f,x,l:eval("f("*l+"*x"+")"*l)
r=lambda i:e("r(i-1)+"*(i>1)+"[i]")
eval
edycji zwraca[0]
lub używa rekurencji, aby uzyskać poprzednie wyniki i dodaje bieżący indeks do listy. Ewaluuje to.a=lambda f,a:eval("f(a["+
r (len (a))[1:-1].replace(",","-1],a[")+"-1])")
a
. Ewaluuje to!f=lambda f,x,l:eval("f("*len(l)+"x,["+
r (len (l))[1:-1].replace(",","-1]),l[")+"-1])")
t=lambda f,n,x:eval("[f("+
r (x) [n-1:].replace(",","),f(")[1:-1]+")]")
Mapa, gniazdo, zasięg, zastosowanie, złożenie, tabela.
Dzięki @Zgarb za lambda za zasięg!
źródło
r=lambda i:[]if i<1 else r(i-1)+[i]
? Żadnych pętli, tylko rekurencja.eval
aby pokazać im, że pętle nie są takie złe :)e=eval
:r=lambda i:e("r(i-1)+"*(i>1)+"[i]")
JavaScript ES6, 197 * 0,9 = 177,3 bajtów
Mapa (
M=(f,l)=>F((a,b)=>[...a,f(b)],[],l)
):Używa opcji Fold, aby połączyć wyniki
f
zastosowane do każdego członka zl
pustej listy. Korzystanie z wbudowanych funkcji ogranicza to doM=(f,l)=>l.map(f)
(nie korzystałeś z niego, ponieważ wydaje się tani ...?).Nest (
N=(f,x,n)=>f(--n?N(f,x,n):x)
):Zastosuj
f
rekurencyjnie, ażn
zmniejszy się do 0.Apply (
A=(f,l)=>f(...l)
):Używa spread (
...
) operator może zastosowaćl
naf
.Zakres (
R=n=>n--?[...R(n),n+1]:[]
):Łączenie
n
z rekurencyjnym wywołaniem zakresu, dopóki nien
zostanie zmniejszone do 0.Fold (
F=(f,x,l,n=l.length)=>n--?f(F(f,x,l,n),l[n]):x
):Stosuje rekurencyjne wywołanie Fold i
n
„th elementul
dof
aż”n
jest zmniejszane do 0. Użycie wbudowanych funkcji zmniejsza toF=(f,x,l)=>l.reduce(f,x)
(ponownie, wydawało się tanie…).Tabela (
T=(f,i)=>([n,x]=i,M(q=>f(q+n-1),R(x-n+1)))
):Pierwsze inicjuje
n
ix
do Imin i IMAX pomocą rozpad ([n,x]=i
), a następnie wykorzystuje zakres skonstruować tabelę wartości z Imin Imax.f
jest następnie nakładany na tabelę za pomocą mapy, a wynik jest zwracany.źródło
Python 3, 218 bajtów
Nieczytelna wersja:
(Więcej) czytelna wersja:
Będzie to jedna lambda na raz:
Funkcja mapy
P
P=lambda f,x:[f(_)for _ in x]
Po prostu prosty iterator. Nie ma tu wiele do powiedzenia.
Funkcja gniazda
Y
Y=lambda f,x,z:Y(f,f(x),z-1)if z else x
Powtarzanie aż do
z
zera, zastosowanie zaf
każdym razem. Na końcu klauzula if wydaje się niezgrabna; być może istnieje lepszy sposób na zakończenie rekurencji.Zastosuj funkcję
T
T=lambda f,x:f(*x)
Python ma fajnego operatora ekspansji, który wykonałby dla mnie wszystkie ciężkie zadania.
Funkcja zakresu
H
H=lambda f,x=0:(H(f-1)if~-f else[])+[f]
Ten był trudniejszy niż się spodziewałem. Skończyło się na rekurencyjnym podejściu. Ponownie, konstrukcja if-else zajmuje dużo bajtów i uważam, że można ją poprawić. Dlaczego ma manekina
x=0
, pytasz? Jest tak, że kiedy go skompresujęexec
, mogę go wymienić=lambda f,x
zamiast po prostu=lambda f
.Funkcja składania
O
O=lambda f,x,z:O(f,f(x,z[0]),z[1:])if z else x
Całkiem zadowolony z tego. Po prostu wycina pierwszy element tablicy za każdym razem, gdy się powtórzy, dopóki nic nie pozostanie.
Funkcja tabeli
N
N=lambda f,x:(N(f,[x[0],x[1]-1])if x[1]-x[0]else[])+[f(x[1])]
Ten jest okropny i jestem pewien, że jest miejsce na ulepszenia. Próbowałem użyć funkcji zakresu i mapy zdefiniowanych wcześniej dla pewnego
map(f,range(x,y))
rodzaju konstrukcji, ale bez większego powodzenia. Skończyło się na strasznym rekurencyjnym podejściu, które dzieli pewne podobieństwo do funkcji zakresu.Wszystkie lambdas są opakowane w sposób
exec
zreplace
skrócić liczbę bajtów znacząco.źródło
[f(_)for _ in x]
co można skrócićmap(f,x)
, ale potem przypomniałem sobie, jakie to wyzwanieJulia, 181 bajtów
Brak premii dla mnie; Użyłem pętli swobodnie. Przepraszam szefie, ale pętle w Julii są skuteczne!
Dodanie elips po argumencie do funkcji powoduje rozbicie tablicy, krotki lub innych elementów na zwykłe argumenty funkcji. W przeciwnym razie funkcja pomyśli, że próbujesz przekazać tablicę (lub krotkę itp.). Nie ma to wpływu na pojedyncze argumenty.
Nazwy funkcji:
M
N
A
R
F
T
źródło
tinylisp , 325 * 0,9 = 292,5
Język jest nowszy od pytania, ale i tak nie wygra.
Definiuje funkcje
A
(zastosuj),M
(mapa),N
(gniazdo),R
(zakres),T
(tabela) iF
(złóż) wraz z kilkoma funkcjami pomocniczymi.T
oczekuje listy dwóch liczb całkowitych jako drugiego argumentu.Tinylisp nie ma nawet żadnych konstrukcji pętli; wszystko odbywa się za pomocą rekurencji. Niektóre z tych funkcji nie są rekurencyjne , więc jeśli wywołasz je na dużych listach, prawdopodobnie zepsują stos wywołań. Można je wszystkie zaimplementować za pomocą rekurencji ogona ... ale zajmie to więcej bajtów, a to jest golf golfowy.
Oto rozszerzona wersja z białymi spacjami i prawdziwymi słowami nazw, które powinny być dość czytelne, jeśli znasz Lisp. (Aliasowałem większość wbudowanych funkcji Tinylisp z wyjątkiem
q
(quote) ii
(if).)Dalsze wyjaśnienia dostępne na żądanie.
Próbka wyjściowa
Korzysta ze środowiska REPL z mojej referencyjnej implementacji. Użyłem
q
(quote) dla funkcji unary is
(odejmij) jako funkcji binarnej dla tych przykładów, a także funkcji@
(zdefiniowanej w tym kodzie), która zwraca listę jej argumentów.źródło
Python 2.x: 450,6 bajtów (493 bajtów przed 10% rabatem)
Odpowiedź w golfa:
To pytanie było zabawne. Postanowiłem napisać moje funkcje bez użycia ekwiwalentów Pythona (choć może to być poprawna luka) i napisać funkcje tak, jakby Python obsługiwał rekurencję ogona. Aby to zadziałało, użyłem wielu opcjonalnych parametrów, które pozwalają, aby wymagane połączenia nadal działały.
Poniżej mam niepoznane listy dla każdej funkcji.
Apply
:Map
:Nest
:Zauważ, że ta funkcja wymaga, aby przekazany
function
mógł reprezentować wiele argumentów zmiennie. Innym podejściem byłoby wymuszenie, aby funkcja zawsze otrzymywała jedną listę, ale wymagałoby to, aby przekazywane funkcje mogły interpretować listy argumentów. W każdym razie były pewne założenia, więc wybrałem ten, który lepiej pasuje do reszty systemu.Range
:Fold
:Table
:Oto przykładowe dane wyjściowe przy użyciu następujących funkcji pomocniczych:
źródło
Cejlon,
370 * 0,9 = 333364 * 0,9 = 327,4Większość tych funkcji jest już dostępna w pakiecie językowym Cejlonu (choć czasem z nieco inną sygnaturą), ale definiujemy je tutaj, zgodnie z żądaniem w pytaniu.
Właściwie tylko dwie funkcje (
t
if
) faktycznie korzystają z rekurencji (odpowiednio nad listami i liczbami całkowitymi), inne oparte są na nich. (Apply jest nieco odstające, tak naprawdę nie odnosi się do innych.)Interpretuję „Listę” jako sekwencyjny typ Cejlona, który jest niezmienną uporządkowaną (być może pustą) sekwencją elementów.
[R*]
oznaczaSequential<R>
- z jakiegoś powodu możemy to również napisaćR[]
, który jest o jeden bajt krótszy.Typem funkcji jest
Callable<R, A>
, gdzieA
jest krotką dla argumentów, na przykład[X, Y, Z]
(np. Jakiś podtypAnything[]
). Jako skrót możemy napisaćR(X,Y,Z)
zamiastCallable<R,[X,Y,Z]>
.I alias
Integer
jakI
zaoszczędzić trochę bajtów.Oto sformatowana (i nieco skomentowana) wersja:
Korzystanie z „pętli”
Tabela i mapa mogą być zaimplementowane krócej za pomocą pętli (w rzeczywistości, rozumienie sekwencji):
Chociaż nie jestem pewien, czy użycie
..
operatora dla zakresu liczb całkowitych liczy się jako użycie wbudowanej funkcji. Jeśli jest to dozwolone, wynikowy kod jest tutaj, długość 312:(Można go jeszcze skrócić, definiując
r(I i) => 1..i
, co daje wynik 301. Chociaż wygląda to jeszcze bardziej na oszustwo).Jeśli
..
nie jest to dozwolone, będziemy musieli wprowadzić go ponownie. Możemy używać tych implementacji do (r
i powyżej):t
m
Daje to 348 bajtów, lepiej niż wersja całkowicie rekurencyjna, ale nie po zastosowaniu premii.
źródło
Groovy (146 bajtów) (146 * 90% = 131,4)
PS Nie wiem, co w tym kontekście traktujesz jako „pętlę”, zastosowałem premię dopiero po tym, jak powiedziano mi to w komentarzach OP, i usunę ją, jeśli 2-3 dodatkowych użytkowników powie te funkcje i iteratory są pętle i że nie zasługuję na bonus. Ponadto, jeśli chcesz zadzwonić do mnie z powodu korzystania z 1..it, zrób to, a ja go przerobię / zaktualizuję moje bajtowe.
Przykład wejścia / wyjścia
Wydajność
Wypróbuj sam: https://groovyconsole.appspot.com/edit/5203951758606336
źródło