Почему список аргументов как ArraySeq? - PullRequest
18 голосов
/ 21 ноября 2011

Рассмотрим следующую функцию:

user> (defn first-args [& args]
            (args 0))
#'user/first-args
user> (first-args 1 2 3) ;=> clojure.lang.ArraySeq cannot be cast to clojure.lang.IFn

Почему список аргументов clojure.lang.ArraySeq, а не что-то более распространенное, например PersistentVector? Или почему ArraySeq не реализует IFn? Причины производительности? Похоже, что вы должны знать базовую реализацию вещей во время выполнения Clojure. Не стесняйтесь просветить меня.

PS: этот вопрос не о том, "это идиоматизм или нет?" Просто спрашиваю, почему это так.

Ответы [ 3 ]

23 голосов
/ 21 ноября 2011
(defn first-args [& args]
  (first args))

(apply first-args (range)) 
;=> 0

Вы можете применить функцию к бесконечной последовательности аргументов, потребляя элементы только по мере необходимости. Если бы & аргументы должны были быть вектором (или чем-то более конкретным, чем ISeq), это было бы невозможно.

Что касается того, почему seqs не вызывается: это будет поощрять использование их способом, который работает очень плохо.

4 голосов
/ 21 ноября 2011

Другие ответы уже хороши, но просто хотел представить альтернативу для достижения того же эффекта:

(defn first-args [first-arg & others] 
  first-arg)

(first-args 1 2 3)
=> 1

т.е. Вы можете явно указать первый аргумент в определении функции.

0 голосов
/ 21 ноября 2011

Вы вызываете args как функцию в строке 2. На самом деле вы хотите:

(defn first-args [& args]
  (first args))

ArraySeq на самом деле более «распространен», чем Vector, потому что Vector наследует ISeq.Вот почему вы не можете сделать (get args 0) здесь, что, как вам кажется, нужно назвать, потому что это работает только для карт и векторов, а не для любого ISeq (например, списка).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...