Używając wybranego języka, napisz funkcję, która pobiera zmienną liczbę argumentów i zwraca liczbę argumentów, z którymi została wywołana.
Specyfika:
- Twój język musi obsługiwać różne funkcje argumentów: coś, co wymaga dowolnej liczby argumentów i zwraca wartość.
- Parametry muszą być przekazywane indywidualnie. Oznacza to, że przekazanie tablicy będzie liczyło się tylko dla jednego parametru. Możesz użyć tablicy „wszystkie przekazane argumenty”, jeśli Twój język ją obsługuje; ograniczenie dotyczy sposobu wywoływania funkcji.
- Kod wywołujący tę funkcję nie może być wymagany do przekazania liczby argumentów w źródle . Jeśli kompilator wstawi liczbę argumentów jako część konwencji wywoływania, jest to dozwolone.
- Argumenty mogą być dowolnego typu. Możesz obsługiwać tylko jeden typ (np. Tylko obsługa
int
jest nadal ważna), dowolne typy (dozwolony jest dowolny typ argumentu) lub dowolna kombinacja typów argumentów (np. Pierwszy argument toint
reszta to łańcuchy). - Twoja funkcja może mieć maksymalną liczbę argumentów (zwłaszcza, że zasoby są skończone), ale musi obsługiwać co najmniej 2 argumenty.
Próbki:
f()
zwraca0
f(1)
lubf("a")
wraca1
f([1, 2, 3])
zwraca,1
gdy jest przekazywana tablica, a nie 3 argumentyf(1, 10)
lubf(1, "a")
wraca2
Ponieważ jest to gra w golfa kodowego, zwycięskim rozwiązaniem jest takie, które wykorzystuje najmniejszą liczbę bajtów.
Odpowiedzi:
Amstrad CPC Z80 wywołanie binarne z języka BASIC, 1 bajt, kodowane szesnastkowo
(Również wersje 2 i 5 bajtowe, patrz poniżej)
Po wejściu do rozmowy liczba przekazanych parametrów będzie w
A
rejestrze. Kod po prostu zwraca natychmiast. W Z80 nie ma pojęcia wartości zwracanych, tylko stany wejścia i wyjścia. Wartość jest po prostu „dostępna” w rejestrze, ponieważ kod nie zmienia żadnych warunków wejściowych, z wyjątkiemPC
(licznika programu) iSP
(wskaźnika stosu). Jednak wartość inA
nie jest dostępna dla BASICa i zostaje niemal natychmiast zastąpiona.Przykłady:
A
= 2A
= 1A
= 0Na życzenie oto kod, który udostępnia wartość w języku BASIC. Byłem bardzo zaskoczony, gdy udało mi się to zrobić w zaledwie 5 bajtów !:
Kod maszynowy:
Przy wejściu:
AF
- rejestry akumulatorów i flag (traktowane jako dwa rejestry 8-bitowe)A
zawiera liczbę przekazanych parametrów, maksymalnie do 32 parametrówF
. Wygląda na to, że wszystkie flagi zostały RESETOWANE0
, z wyjątkiem dwóch niezdefiniowanych flag, które są obydwoma1
.Z
Flag (zero) jest ustawiony1
, jeśli nie zostały przekazane w żadnych parametrówBC
B
- 32 minus liczba parametrów (A
+B
= 32)C
-&FF
DE
- Adres ostatniego parametru lub adres wywołujący, jeśli nie przekazano żadnych parametrówHL
- Adres pierwszego bajtu po aktualnie wykonywanym tokenizowanym poleceniu BASIC (jako program lub w trybie polecenia natychmiastowego)IX
- Adres stosu wskaźnika do ostatniego parametruIY
-&0000
Kod
L
OAD
s adres wskazywany przezDE
z wartością wA
INC
rementsDE
XOR
sA
(zA
), dając&00
L
OAD
s wartośćA
do adresu wskazywanego przezDE
RET
urnyPrzy wyjściu:
A
jest zniszczony (zawsze&00
)DE
jest zniszczony (zawsze o jeden wyższy niż przy wejściu)Podstawy
Amstrad basic ma tylko trzy typy danych oraz proste tablice. Domyślnie wszystkie zmienne BASIC są PRAWDZIWE (podpisane, 32-bitowa mantysa, 8-bitowy wykładnik), co można jednoznacznie określić
!
. W przypadku użycia INTEGER (podpisany, 16 bitów)%
i STRING (długość łańcucha 1 bajt, dane do 255 bajtów, sejf binarny)$
:x
- PRAWDZIWE (niejawne)x!
- PRAWDZIWE (jednoznaczne)x%
- INTEGERx$
- STRUNOWYMożna również użyć
DEFINT
,DEFREAL
iDEFSTR
z jednej litery lub zakresu dwoma pojedynczymi literami, aby określić typ domyślny dla wszystkich zmiennych wyjściowych z tego pisma, podobnie jak FORTRAN.DEFSTR a
DEFINT x-z
Teraz:
a
- STRING (domyślnie)i
- PRAWDZIWE (niejawne)x
- INTEGER (domyślnie)x$
- STRING (jednoznaczne)Najłatwiejszym typem do pracy jest liczba całkowita. Kod maszynowy oczekuje, że ostatni parametr zostanie przekazany przez adres, a nie wartość, dlatego
@
jest poprzedzony zmienną. Zmienna zwracana jest liczona jako jeden zCALL
parametrów s.Kod maszynowy jest wywoływany z BASIC w następujący sposób (przy założeniu, że jest załadowany do pamięci pod adresem
&8000
):n%
= 4To zawsze daje poprawny wynik, niezależnie od wartości początkowej
n%
.W przypadku wersji 2-bajtowej, która zachowuje wszystkie rejestry wejściowe:
n%
= 4Pomija to pierwsze trzy bajty i daje poprawny wynik tylko wtedy, gdy początkowa wartość
n%
to0
-255
. Działa to, ponieważ Z80 jest little-endian.Parametr zwracany musi zostać zainicjowany przed przekazaniem, w przeciwnym razie BASIC zgłosi
Improper argument
błąd. Na poniższym obrazku drukuję (skrótem,?
ponieważ grałem też w grę!) Wartości zwracane bezpośrednio przed i po wywołaniu, aby pokazać zmianę wartości. Używam tej wartości,&FFFF
ponieważ jest to reprezentacja binarna-1
dla liczby całkowitej ze znakiem. To pokazuje, że program 5-bajtowy poprawnie zapisuje oba bajty, podczas gdy program 2-bajtowy zapisuje tylko bajt niski i zakłada, że bajt najwyższy już istnieje&00
.źródło
A
, jeśli to jest jak możesz to zrobić z poziomu BASIC). Nie chodzi o to, że jest w tym coś złego, ale może być ciekawszą odpowiedzią na przestrzeganie istniejącej konwencji calli.A
jest taka sama natychmiast poRET
instrukcji. Żywotność wartości wA
jest bardzo krótka, ponieważ jest to akumulator. Nie ma czegoś takiego jakx = CALL &8000, 42
. Musiałby to byćCALL &8000, x, 42
, i dodatkowy kod Z80, ale wtedyx
byłoby2
nie1
.&00
s -NOP
no-ops. Można dodać kolejny bajt, aby uczynić go bezpieczniejszym, ale oczywiście bez parametru zwracającego nie może niczego ustawić.Java (JDK 10) , 11 bajtów
Wypróbuj online!
źródło
interface x{void f(Object...a);}
to zdefiniowania, a ta lambda musi być albo zapisana w zmiennej tego typu interfejsu, albo przekazana do metody oczekującej tego typu interfejsu, więc nie jestem pewien, czy liczy się to wyzwanie (nawet choć zwykle javanki są dozwolone w wyzwaniach codegolf)JavaScript, 15 bajtów
Array.prototype.push
Funkcja przyjmuje dowolną liczbę argumentów, dodaje je do swojej tablicy i zwraca rozmiar tablicy. Dlategopush
funkcja użyta w pustej tablicy zwraca liczbę dostarczonych argumentówpush
.Po
.bind(0)
prostu nadajepush
funkcji stałąthis
wartość, dzięki czemu można ją zapisać w zmiennej. W rzeczywistości 7-bajtowy identyfikator[].push
może być używany dosłownie (ale nie przypisany) bezbind
:źródło
JavaScript (ES6), 16 bajtów
Pokaż fragment kodu
źródło
Haskell ,
1081079594 bajtówWypróbuj online!
To było zaskakująco trudne, ale dobrze się bawiłem, próbując dowiedzieć się, jak wdrożyć coś, co jest trywialne w imperatywnych językach.
źródło
f
jest opcjonalne, jeśli powiesz, żez 0
jest funkcją bez powiązania, więcmain = print $ ((z 0) pi 0 () [] :: Int)
działa.z 0
::Int
należy je liczyć w liczbie bajtów, ponieważ rodzaj odpowiedzi musi zostać zadeklarowany prędzej czy później, jak wmain = print $ ((z 0 :: Double -> Integer -> () -> [a] -> (Int->Int->Int) -> IO () -> Int) pi 0 () [] (+) main)
. Myślę też, że działa to tylko podczas kompilacji, więc coś takiegofoldl(\a b->a b) (z 0) $ [1..5])::Int
nie działa. Tak czy inaczej, to świetne rzeczy.s/imperative/non-curry/
Python 3 , 15 bajtów
Wypróbuj online!
źródło
Zsh ,
75 bajtówWypróbuj online!
źródło
f(){ echo $#; }
Brain-Flak , 6 bajtów
Moje pierwsze rozwiązanie Brain-Flak godne opublikowania, myślę, że jest to właściwe narzędzie do tego zadania:
Wypróbuj online!
Wyjaśnienie
Podczas wykonywania programu Brain-Flak początkowo lewy stos zawiera wszystkie argumenty. Stamtąd jest to po prostu kwestia:
źródło
Wolfram Language (Mathematica) , 11 bajtów
Wypróbuj online!
Sugerowane przez JungHwan Min. Niektóre ograniczenia (dane wejściowe muszą być prostokątne), ale nie jesteśmy zobowiązani do obsługi danych arbitralnych.
11 bajtów
Wypróbuj online!
Kolejne 11-bajtowe rozwiązanie zaproponowane przez Martina Endera. Wydaje się, że to błąd, gdy nie ma jednego wejścia, ale nadal zwraca poprawną wartość we wszystkich przypadkach.
12 bajtów
Wypróbuj online!
Moje oryginalne rozwiązanie.
W Mathematica
##
oznacza różnorodną liczbę argumentów w funkcji.{
i}
zawija je w listę iLength@
zajmuje długość tej listy.&
na końcu zamienia to w faktyczną funkcję.źródło
R , 30 bajtów
Wypróbuj online!
źródło
function(...)nargs()
ma 20 bajtów, alelength(...)
początkowo korzystałem z niego, dopóki nie przejrzałemnargs
funkcji podobnej do Google.list(...)
logiczny, więcsum()
można go użyć, ale to trudne: /...length()
robi to samo, colength(list(...))
Bash, 12 bajtów (dzięki paxdiablo za oszczędność 4)
Skopiuj i wklej po wyświetleniu monitu. Następnie uruchom funkcję n z wiersza polecenia:
źródło
echo $#
:, 7 bajtów. (będzie to jakakolwiek powłoka, której użyjesz do uruchomienia skryptu „./n” za pomocą. tzn. uruchomisz bash? a potem, gdy:./n arg1 ... argn
zostanie to zinterpretowane przez bash.)C ++ 14 (gcc) , 34 bajty
Jako ogólna variadyczna funkcja lambda (wymagany C ++ 14):
Wypróbuj online!
Poprzednia (niepoprawna) odpowiedź: 32 bajty
Brakowało
template<class...T>
i(p)
źródło
p
(i-w
wyłączyć ostrzeżenie).-fpermissive
kosztowałbyś 12 bajtów dla tej opcji? Jeśli nie jest to standard ISO C ++ lub GNU C ++.Ruby , 12 bajtów
Wypróbuj online!
*a
jest zestawem argumentów, dzięki czemua
zużywa wszystkie argumenty przekazane do Proc.a.size
uzyskuje swój rozmiar.źródło
Oktawa , 9 bajtów
Wypróbuj online!
Anonimowa funkcja pobierająca dowolną liczbę argumentów (i dyskretnie odrzucająca partię), i wysyła liczbę argumentów przez wbudowane
nargin
. Nie działa to w MATLAB, gdzie trzebavarargin
by pozwolić na dowolne wiele argumentów.źródło
Perl 6 , 5 bajtów
Dzięki @Joshua za -5 bajtów
Wypróbuj online!
źródło
{+@_}
sub
w Perlu 6 (ale nie w Perlu 5).Perl 5 , 9 bajtów
Wypróbuj online!
źródło
sub
sub
, nie sądzę. Bez niej nie jest to funkcja.sub
PHP, 34 bajty
źródło
function(){return func_num_args();}
(35 bajtów, zamieszczonych poniżej).C # .NET, 11 bajtów
Wypróbuj online.
Wyjaśnienie:
W języku C # .NET
object
jest używany do argumentów wielu typów, umożliwiając przekazywanie liczb całkowitych, ciągów, znaków itp. Jako możliwych danych wejściowych. Na przykład:C # .NET może również mieć ustalony rozmiar opcjonalnych argumentów. Na przykład:
Są też varargs, czyli nieokreślona liczba opcjonalnych argumentów (tego właśnie użyłem w tej odpowiedzi). Na przykład:
Zazwyczaj lambdas są tworzone w ten sposób:
Ale niestety
System.Func
nie obsługujeparams
varargs, więcdelegate
zamiast tego będę musiał utworzyć :To moja odpowiedź na to wyzwanie, którą można znaleźć w połączonym kodzie testowym TIO.
Jedynym ograniczeniem jest to, że wprowadzenie rzeczywistej wartości
object[]
podobnejf(new object[]{1,2,3})
spowoduje 3 zamiast 1f(new int[]{1,2,3})
, nadal spowoduje 1, ponieważ interpretuje toint[]
jako pojedynczyobject
. Aby miećobject[]
parametr należy interpretować jako pojedynczego obiektu, jak również może być lanego do obiektu tak:f((object)new object[]{1,2,3})
.źródło
object[]
parametrów, abyobject
coś takiego:f((object)new object[]{1,2,3});
. Nie ma sposobu na rozróżnienie pomiędzyf(new object[]{1,2,3});
if(1,2,3);
o ile mogłem znaleźć.f(1, new object[]{1,2,3})
znowu się nie udaje . Nie jestem pewien, czy można znaleźć rozwiązanie tego problemu.Dodos ,
3231 bajtówWypróbuj online!
Używa funkcji przyrostowej Dennisa.
Wyjaśnienie
Alternatywnie, 32 bajty bez rekurencji w funkcji celu (dzięki @Leo )
Wypróbuj online!
Wyjaśnienie
źródło
C ++, 72 bajty
Oszczędza bajty, pracując tylko z ints.
źródło
sizeof...
.Rdza, 57 bajtów
Wyjaśnienie:
Test:
źródło
PHP, 35 bajtów
ręczne wprowadzanie
źródło
Common Lisp , 28 bajtów
Wypróbuj online!
źródło
Dodaj ++ , 3 bajty
Wypróbuj online!
źródło
PHP, 11 bajtów
Wypróbuj online: 1 wejście | 3 wejścia
źródło
Partia,
5049 bajtówBrak wbudowanego w Batch, więc musimy iść do starej szkoły. Zapisano 1 bajt dzięki @IsmaelMiguel. Dane wyjściowe za pomocą kodu wyjścia lub zapisanie 3 bajtów, jeśli dane wyjściowe za pomocą zmiennej globalnej są prawidłowe. Przykład zastosowania w pełnym programie:
źródło
:a|set r=0&for %%a in (%*)do set/ar+=1
(|
= nowa linia w stylu Windows). To rozwiązanie ma 38 bajtów. Aby go wykonać, wykonajcall :a <args>
zgoto :eof
funkcją przed, która jest wartością dostępną wewnątrz zmiennejr
. Jeśli chcesz zachować swoje rozwiązanie, usuń/a
pierwszyset
i usuń je@
.x86 32-bitowa (i386) funkcja kodu maszynowego, 13 bajtów
Konwencja wywoływania : i386 System V (stos argumentów), ze wskaźnikiem NULL jako wartownikiem / terminatorem listy końca argumentu . (Clobbers EDI, poza tym zgodny z SysV).
C (i asm) nie przekazują informacji o typie do funkcji variadic, więc opis OP dotyczący przekazywania liczb całkowitych lub tablic bez wyraźnych informacji o typie może być zaimplementowany tylko w konwencji, która przekazała jakiś obiekt struct / class (lub wskaźniki do takich ), a nie same liczby całkowite na stosie. Postanowiłem więc założyć, że wszystkie argumenty nie były wskaźnikami NULL, a obiekt wywołujący przechodzi terminator NULL.
Lista wskaźników zakończona wartością NULL argumentów jest faktycznie używana w C dla funkcji takich jak POSIX
execl(3)
:int execl(const char *path, const char *arg, ... /* (char *) NULL */);
C nie zezwala na
int foo(...);
prototypy bez ustalonego arg, aleint foo();
oznacza to samo: args nieokreślony. (W przeciwieństwie do C ++, gdzie to oznaczaint foo(void)
). W każdym razie jest to odpowiedź asm. Koncentrowanie kompilatora C w celu bezpośredniego wywołania tej funkcji jest interesujące, ale nie wymagane.nasm -felf32 -l/dev/stdout arg-count.asm
z usuniętymi niektórymi wierszami komentarza.Pytanie pokazuje, że funkcja musi mieć możliwość zwrócenia 0, i postanowiłem spełnić to wymaganie, nie włączając końcowego wskaźnika NULL do liczby argumentów. Jednak kosztuje to 1 bajt. (W przypadku wersji 12-bajtowej usuń LEA i odkomentuj
scasd
zewnętrzną pętlę ixchg
, ale niedec edx
. Użyłem LEA, ponieważ kosztuje tyle samo, co pozostałe trzy instrukcje razem, ale jest bardziej wydajna, więc funkcja jest mniejsza ups.)Osoba dzwoniąca C do testowania :
Zbudowany z:
-fcall-used-edi
jest wymagane nawet przy -O0, aby powiedzieć gcc, aby zakładał, że funkcje zamykają sięedi
bez zapisywania / przywracania, ponieważ użyłem tak wielu wywołań w jednej instrukcji C (printf
wywołanie), że nawet-O0
używał EDI. Wydaje się, że gcc może bezpieczniemain
zablokować EDI z własnego obiektu wywołującego (w kodzie CRT), w Linuksie z glibc, ale poza tym mieszanie / dopasowanie kodu skompilowanego z innym jest całkowicie fałszywe-fcall-used-reg
. Nie ma żadnej__attribute__
wersji, która pozwalałaby nam zadeklarować funkcje asm z niestandardowymi konwencjami wywoływania innymi niż zwykle.Dwie inne wersje również miały 13 bajtów: ta oparta na
loopne
wartości zwraca wartość zbyt wysoką o 1.Ta wersja używa rep scasd zamiast pętli, ale pobiera modulo 256 zliczania argów (lub ograniczona do 256, jeśli górne bajty
ecx
są 0 przy wejściu!)Zabawne jest, że kolejna wersja oparta na
inc eax
/pop edx
/test edx,edx
/jnz
ma 13 bajtów. Jest to konwencja callee-pops, która nigdy nie jest wykorzystywana przez implementacje języka C do funkcji variadic. (Wstawiłem add add do ecx, a jmp ecx zamiast ret. (Lub push / ret, aby nie zepsuć stosu predykcji adresu zwrotnego).źródło
R , 20 bajtów
Wypróbuj online!
R ma właśnie taką funkcję .
źródło
JavaScript, 35 bajtów
źródło
Kalafior , 16 bajtów
Wypróbuj online!
źródło