Используя выбранный вами язык, напишите функцию, которая принимает переменное число аргументов и возвращает количество аргументов, с которыми она была вызвана.
Особенности:
- Ваш язык должен поддерживать функции аргументов с переменным аргументом: что-то вызываемое, которое принимает произвольное количество аргументов и возвращает значение.
- Параметры должны передаваться индивидуально. Это означает, что передача массива будет учитываться только для одного параметра. Вы можете использовать массив «все переданные аргументы», если ваш язык поддерживает его; ограничение заключается в том, как вызывается функция.
- Код, вызывающий эту функцию, не обязан передавать количество аргументов в ее источнике . Если компилятор вставляет количество аргументов как часть соглашения о вызовах, это разрешается.
- Аргументы могут быть любого типа, который вы хотите. Вы можете поддерживать только один тип (например, поддерживается только поддержка
int
), произвольные типы (разрешен любой тип аргумента) или любую комбинацию типов аргумента (например, первый аргумент isint
, остальные - строки). - Ваша функция может иметь максимальное количество аргументов (особенно если ресурсы конечны), но должна поддерживать как минимум 2 аргумента.
Образцы:
f()
возвращается0
f(1)
илиf("a")
возвращается1
f([1, 2, 3])
возвращает1
как передается массив, а не 3 аргументаf(1, 10)
илиf(1, "a")
возвращается2
Поскольку это код-гольф, выигрышное решение - это то, которое использует наименьшее количество байтов.
Ответы:
Бинарный вызов Amstrad CPC Z80 от BASIC, 1 байт, шестнадцатеричный код
(Также 2- и 5-байтовые версии, см. Ниже)
При поступлении на звонок количество передаваемых параметров будет в
A
реестре. Код просто возвращается немедленно. В Z80 нет понятия возвращаемых значений, только состояния входа и выхода. Значение просто «там» доступно в регистре, поскольку код не изменяет входные условия, кромеPC
(счетчик программы) иSP
(указатель стека). Однако значение вA
недоступно для Бейсика и почти сразу же перезаписывается.Примеры:
A
= 2A
= 1A
= 0По запросу, здесь есть некоторый код, который делает значение доступным в бейсике. Я был очень удивлен, обнаружив, что это можно сделать всего за 5 байтов!
Машинный код:
На входе:
AF
- регистры аккумулятора и флагов (рассматриваются как два 8-битных регистра)A
содержит количество переданных параметров, максимум 32 параметраF
. Кажется, у него есть все флаги RESET0
, кроме двух неопределенных флагов, которые оба1
.Z
Флаг (ноль) установлен в положение,1
если не было проходили в параметрыBC
B
- 32 минус количество параметров (A
+B
= 32)C
-&FF
DE
- адрес последнего параметра или адрес вызывающего абонента, если параметры не были переданы вHL
- Адрес первого байта после токенизированной команды BASIC, выполняемой в данный момент (либо в виде программы, либо в режиме немедленной команды)IX
- адрес стека указателя на последний параметрIY
-&0000
Код
L
oaD
s адрес, на который указываетDE
значение вA
INC
rementsDE
XOR
сA
(сA
), давая&00
L
oaD
s значение вA
адрес, на который указываетDE
RET
урныНа выходе:
A
уничтожен (это всегда&00
)DE
уничтожается (всегда на единицу выше, чем при входе)Базовый
Amstrad basic имеет только три типа данных плюс простые массивы. По умолчанию все переменные BASIC имеют значение REAL (со знаком, 32-битная мантисса, 8-битная экспонента), что можно сделать явным с помощью
!
. Для использования%
в формате INTEGER (со знаком, 16 бит) и для STRING (длина строки в 1 байт, до 255 байтов символьных данных, бинарный код) используйте$
:x
- НАСТОЯЩИЙ (неявный)x!
- НАСТОЯЩИЙ (явный)x%
- INTEGERx$
- STRINGВы также можете использовать
DEFINT
,DEFREAL
иDEFSTR
с одной буквой или диапазоном двух отдельных букв , чтобы указать тип по умолчанию для всех переменных , начинающихся с этой буквой, похожей на FORTRAN.DEFSTR a
DEFINT x-z
В настоящее время:
a
- STRING (неявный)i
- НАСТОЯЩИЙ (неявный)x
- INTEGER (неявный)x$
- STRING (явный)Самый простой тип для работы с целым числом. Машинный код ожидает, что последний параметр будет передан по адресу, а не по значению, поэтому
@
к переменной добавляется префикс. Возвращаемая переменная считается одним изCALL
параметров s.Машинный код вызывается из BASIC следующим образом (при условии, что он загружен в память по адресу
&8000
):n%
= 4Это всегда даст правильный результат, независимо от начального значения
n%
.Для 2-байтовой версии, которая сохраняет все входные регистры:
n%
= 4Это пропускает первые три байта и дает правильный результат, только если начальное значение
n%
равно0
-255
. Это работает, потому что Z80 имеет младший порядок.Возвращаемый параметр должен быть инициализирован перед передачей, в противном случае BASIC выдаст
Improper argument
ошибку. На изображении ниже я печатаю (с ярлыком,?
так как я тоже играл в гольф!) Возвращаемые значения непосредственно перед и после вызова, чтобы показать изменение значения. Я использую значение,&FFFF
потому что это двоичное представление-1
для целого числа со знаком. Это демонстрирует, что 5-байтовая программа правильно записывает оба байта, тогда как 2-байтовая программа записывает только младший байт и предполагает, что старший байт уже есть&00
.источник
A
, если это так). как вы могли бы сделать это из бейсика). Не то, чтобы в этом было что-то не так, но это может быть более интересным ответом следовать существующему соглашению о вызовах.A
то же самое сразу послеRET
инструкции. Срок службы значения вA
очень короткий, так как это аккумулятор. Там нет такого понятия, какx = CALL &8000, 42
. Это должно было бытьCALL &8000, x, 42
и дополнительный код Z80, но тогдаx
было бы2
, нет1
.&00
s -NOP
no-ops. Можно сделать еще один байт, чтобы сделать его более безопасным, но, конечно, без параметра возврата он ничего не может установить.Java (JDK 10) , 11 байт
Попробуйте онлайн!
источник
interface x{void f(Object...a);}
определения, и эта лямбда должна быть либо сохранена в переменной этого типа интерфейса, либо передана методу, ожидающему этот тип интерфейса, так что я не совсем уверен, что это имеет значение для этой проблемы (даже хотя обычно ява-лямбды разрешены в соревнованиях по кодгольфу)JavaScript, 15 байт
Array.prototype.push
Функция принимает любое количество аргументов, добавляет их в массив и возвращает размер массива. Поэтомуpush
функция, используемая в пустом массиве, возвращает количество аргументов, переданныхpush
.Он
.bind(0)
просто даетpush
функции фиксированноеthis
значение, чтобы ее можно было сохранить в переменной. Фактически, 7-байтовый идентификатор[].push
можно использовать буквально (но не назначать) безbind
:источник
JavaScript (ES6), 16 байт
Показать фрагмент кода
источник
Haskell ,
1081079594 байтовПопробуйте онлайн!
Работать с этим было на удивление сложно, но мне было интересно узнать, как реализовать что-то тривиальное в императивных языках.
источник
f
необязательно, если вы говоритеz 0
, что функция без привязки, так чтоmain = print $ ((z 0) pi 0 () [] :: Int)
работает.z 0
::Int
в счетчике байтов должно учитываться число, поскольку тип ответа должен быть объявлен рано или поздно, как вmain = print $ ((z 0 :: Double -> Integer -> () -> [a] -> (Int->Int->Int) -> IO () -> Int) pi 0 () [] (+) main)
. Я также думаю, что это работает только во время компиляции, поэтому что-то вродеfoldl(\a b->a b) (z 0) $ [1..5])::Int
не может работать. В любом случае, это отличные вещи.s/imperative/non-curry/
Python 3 , 15 байт
Попробуйте онлайн!
источник
Зш ,
75 байтПопробуйте онлайн!
источник
f(){ echo $#; }
Brain-Flak , 6 байтов
Мое первое решение Brain-Flak, достойное публикации, я думаю, это правильный инструмент для этой работы:
Попробуйте онлайн!
объяснение
При выполнении программы Brain-Flak изначально левый стек содержит все аргументы. Оттуда это просто вопрос:
источник
Wolfram Language (Mathematica) , 11 байт
Попробуйте онлайн!
Предложенный JungHwan Мин. Некоторые ограничения (ввод должен быть прямоугольным), но мы не обязаны обрабатывать произвольный ввод.
11 байт
Попробуйте онлайн!
Еще одно 11-байтовое решение, предложенное Мартином Эндером. Это кажется ошибкой, когда нет одного ввода, но оно все равно возвращает правильное значение во всех случаях.
12 байт
Попробуйте онлайн!
Мое оригинальное решение.
В Mathematica
##
обозначает переменное число аргументов в функции.{
и}
оборачивает их в список иLength@
принимает длину этого списка.&
в конце превращает это в реальную функцию.источник
R , 30 байт
Попробуйте онлайн!
источник
function(...)nargs()
составляет 20 байт, но использованиеlength(...)
было моим первоначальным подходом, пока я не прибегнул к гугл-nargs
подобной функции.list(...)
логическое, чтобыsum()
можно было использовать, но это сложно: /...length()
делает то же самое, что иlength(list(...))
Bash, 12 байт (спасибо paxdiablo за сохранение 4)
Скопируйте и вставьте в командной строке bash. Затем запустите функцию n из командной строки:
источник
echo $#
7 байтов. (тогда будет любая оболочка, которую вы используете для запуска скрипта "./n". То есть вы запускаете bash? тогда когда вы:./n arg1 ... argn
это будет интерпретироваться bash.)C ++ 14 (gcc) , 34 байта
Как универсальная переменная лямбда-функция (требуется C ++ 14):
Попробуйте онлайн!
Предыдущий (неверный) ответ: 32 байта
Это было пропущено
template<class...T>
и(p)
источник
p
(и-w
отключить предупреждение).-fpermissive
стоить вам 12 байтов для этого варианта, хотя? Если это не стандарт ISO C ++ или GNU C ++.Рубин , 12 байт
Попробуйте онлайн!
*a
является аргументом, заставляющимa
потреблять все аргументы, передаваемые в Proc.a.size
получает свой размер.источник
Октава , 9 байт
Попробуйте онлайн!
Анонимная функция, принимающая любое количество аргументов (и молча отбрасывающая лот), и выводящая количество аргументов через встроенную функцию
nargin
. Это не работает в MATLAB, где вам нужноvarargin
учесть произвольное множество аргументов.источник
Perl 6, 5 bytes
Thanks @Joshua for -5 bytes
Try it online!
источник
{+@_}
sub
in Perl 6 (not in Perl 5, though).Perl 5, 9 bytes
Try it online!
источник
sub
sub
, I don't think so. It's not a function without it.sub
invalid since the result isn't something you can call or assign to a variablePHP, 34 bytes
источник
function(){return func_num_args();}
(35 bytes, posted below).C# .NET, 11 bytes
Try it online.
Explanation:
In C# .NET
object
is used for multi-type arguments, allowing one to pass integers, strings, characters, etc. as possible inputs. For example:C# .NET can also have a fixed size of optional arguments. For example:
And there are also varargs, which is an undefined amount of optional arguments (which is what I've used in this answer). For example:
Usually lambdas are created like this:
But unfortunately
System.Func
doesn't supportparams
varargs, so I'll have to create adelegate
instead:Which is my answer for this challenge, and can be found in the linked TIO test code.
The only limitation is that inputting an actual
object[]
likef(new object[]{1,2,3})
will result in 3 instead of 1.f(new int[]{1,2,3})
will still result in 1, because it interprets theint[]
as a singleobject
. To have theobject[]
parameter be interpret as a single object as well it can be casted to an object like this:f((object)new object[]{1,2,3})
.источник
object[]
parameters toobject
, like this:f((object)new object[]{1,2,3});
. There is no way to differentiate betweenf(new object[]{1,2,3});
andf(1,2,3);
as far as I could find.f(1, new object[]{1,2,3})
again though. Not sure if a solution for this behavior can be found.Dodos,
3231 bytesTry it online!
Uses Dennis' increment function.
Explanation
Alternatively, 32 bytes without recursion in target function (thanks @Leo)
Try it online!
Explanation
источник
C++, 72 bytes
Saves bytes by only working with ints.
источник
sizeof...
.Rust, 57 bytes
Explanation:
Test:
источник
PHP, 35 bytes
manual entry
источник
Common Lisp, 28 bytes
Try it online!
источник
Add++, 3 bytes
Try it online!
источник
PHP, 11 bytes
Try it online: 1 input | 3 inputs
источник
Batch,
5049 bytesNo builtin in Batch, so we have to go old-school. Saved 1 byte thanks to @IsmaelMiguel. Outputs via exit code, or save 3 bytes if output via global variable is valid. Example of use in a full program:
источник
:a|set r=0&for %%a in (%*)do set/ar+=1
(|
= windows-style newline). This solution is 38 bytes. To execute it, docall :a <args>
with agoto :eof
before the function, being the value available inside the variabler
. If you want to keep your solution, remove the/a
on the firstset
, and remove those@
.x86 32-bit (i386) machine code function, 13 bytes
Calling convention: i386 System V (stack args), with a NULL pointer as a sentinel / terminator for the end-of-arg-list. (Clobbers EDI, otherwise complies with SysV).
C (and asm) don't pass type info to variadic functions, so the OP's description of passing integers or arrays with no explicit type info could only be implemented in a convention that passed some kind of struct / class object (or pointers to such), not bare integers on the stack. So I decided to assume that all the args were non-NULL pointers, and the caller passes a NULL terminator.
A NULL-terminated pointer list of args is actually used in C for functions like POSIX
execl(3)
:int execl(const char *path, const char *arg, ... /* (char *) NULL */);
C doesn't allow
int foo(...);
prototypes with no fixed arg, butint foo();
means the same thing: args unspecified. (Unlike in C++ where it meansint foo(void)
). In any case, this is an asm answer. Coaxing a C compiler to call this function directly is interesting but not required.nasm -felf32 -l/dev/stdout arg-count.asm
with some comment lines removed.The question shows that the function must be able to return 0, and I decided to follow that requirement by not including the terminating NULL pointer in the arg count. This does cost 1 byte, though. (For the 12-byte version, remove the LEA and uncomment the
scasd
outside the loop and thexchg
, but not thedec edx
. I used LEA because it costs the same as those other three instructions put together, but is more efficient, so the function is fewer uops.)C caller for testing:
Built with:
-fcall-used-edi
is required even at -O0 to tell gcc to assume that functions clobberedi
without saving/restoring it, because I used so many calls in one C statement (theprintf
call) that even-O0
was using EDI. It appears to be safe for gcc'smain
to clobber EDI from its own caller (in CRT code), on Linux with glibc, but otherwise it's totally bogus to mix/match code compiled with different-fcall-used-reg
. There's no__attribute__
version of it to let us declare the asm functions with custom calling conventions different from the usual.Two other versions also came in at 13 bytes: this one based on
loopne
returns a value that's too high by 1.This version uses rep scasd instead of a loop, but takes the arg count modulo 256. (Or capped at 256 if the upper bytes of
ecx
are 0 on entry!)Amusingly, yet another version based on
inc eax
/pop edx
/test edx,edx
/jnz
came in at 13 bytes. It's a callee-pops convention, which is never used by C implementations for variadic functions. (I popped the ret addr into ecx, and jmp ecx instead of ret. (Or push/ret to not break the return-address predictor stack).источник
R, 20 bytes
Try it online!
R has a function just for that.
источник
JavaScript, 35 bytes
источник
Cauliflower, 16 bytes
Try it online!
источник