Такой функции нет, вы вольны реализовать и использовать ее по своему усмотрению:
(defn args [& args] args)
(set (map type (apply map args [[1 2 3][4 5 6][7 8 9]])))
=> #{clojure.lang.ArraySeq}
Почему он еще не доступен?
Это редко плодотворный вопрос: мы не только не знаем, что происходит в голове разработчиков, но и практически невозможно просить их обосновать или задокументировать, почему они не что-то сделали. Рассматривалось ли когда-нибудь добавление этой функции? Откуда мы можем знать? Есть ли на самом деле причина, или это произошло само собой?
С другой стороны, я согласен, что args
кажется проще, потому что он передает уже существующую неизменяемую последовательность. Я также могу понять, если вы считаете, что лучше не преобразовывать аргументы в виде постоянного списка, хотя бы из соображений экономии.
Но это не так, как это реализовано, и накладные расходы на использование list
действительно незначительны (и .java#L27" rel="nofollow">специализируется при сборке из экземпляра ArraySeq
). Предполагается, что вы программируете интерфейс и никогда не заглядываете за кулисы, и с этой точки зрения list
и args
эквивалентны, даже если они не возвращают идентичные результаты. .
Вы добавили замечание о лени, и вы правы: если вам когда-нибудь понадобится взять аргументы из функции с переменным числом аргументов и передать их функции, которая работает с последовательностями, версия с list
будет потреблять все заданные аргументы, тогда как args
не будет. В некоторых случаях, как в случае с (apply list (range))
, когда вы буквально передаете бесконечное количество аргументов, это может зависнуть навсегда.
С этой точки зрения маленькая функция args
действительно интересна: вы можете переходить от аргументов к фактическим последовательностям, не создавая потенциальных проблем. Однако я не уверен, как часто это случается на практике. На самом деле, мне трудно найти вариант использования, когда лень в списке аргументов действительно имеет значение, когда дело касается args
. В конце концов, чтобы передать бесконечную последовательность, единственный способ (?) — использовать apply:
(apply f (infinite))
Чтобы иметь вариант использования для args
, это означает, что мы хотим преобразовать список аргументов обратно в один список, чтобы другая функция g могла использовать его как последовательность, например так:
(g (apply args (infinite)))
Но в этом случае мы могли бы напрямую вызвать:
(g (infinite))
В вашем примере g
будет означать cons
внутри lazy-map
, но поскольку f
задано на входе, мы не можем написать (cons (map ...) ...)
напрямую. Таким образом, пример выглядит как реальный вариант использования args
, но вы должны тщательно задокументировать функцию, потому что фрагмент, который вы дали, довольно сложен. Я склонен думать, что предоставление неограниченного количества аргументов функции — это запах кода: должна ли каждая функция с сигнатурой [& args]
избегать использования всех аргументов, потому что данная последовательность может фактически быть бесконечной, как это делает lazy-map
? Я бы предпочел, чтобы один аргумент был ленивой последовательностью для такого использования (и передал identity
при необходимости) вместо всего списка аргументов, чтобы прояснить намерение. Но, в конце концов, я тоже не сильно против использования args
.
Итак, в заключение, если вам не удастся убедить Рича Хикки добавить args
в качестве основной функции, я уверен, что почти никто не захочет зависеть от внешней библиотеки, которая делает именно это1 sup>: это незнакомо, но также тривиально для реализации и в основном бесполезно. Единственная награда — это знать, что вы пропускаете небольшой шаг преобразования, который в большинстве случаев ничего не стоит. Точно так же не беспокойтесь о необходимости выбирать между вектором и списком: это практически не влияет на ваш код, и вы все равно можете изменить код позже, если докажете, что это необходимо. Что касается лени, хотя я согласен с тем, что перенос аргументов в списки или векторы может быть проблематичным с неограниченными списками аргументов, я не уверен, что проблема действительно возникает на практике.
1. Конечно, если оно когда-нибудь достигнет clojure.core
, все тут же скажут, что это фундаментальная операция, которая очень полезна и определенно идиоматична ‹/cynic›.
person
coredump
schedule
24.11.2015
list
. Я не вижу разницы: что делаетlist
преобразующим, а ваше нет? - person coredump   schedule 24.11.2015(type ((fn [& args] args) :foo))
и(type (list :foo))
. - person Sam Estep   schedule 24.11.2015=
и что они имеют одни и те же важные интерфейсы. - person noisesmith   schedule 24.11.2015list
илиvector
, и вы поймете, что я имею в виду. - person Sam Estep   schedule 04.02.2016(apply fn (range))
вы вызываете fn с бесконечным числом непоследовательных аргументов. Но у вас есть точка зрения, и я отредактирую ответ, чтобы отразить этот конкретный аспект. - person coredump   schedule 04.02.2016