Подтвердить что ты не робот

Почему аргумент список как ArraySeq?

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

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

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

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

4b9b3361

Ответ 1

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

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

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

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

Ответ 2

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

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

(first-args 1 2 3)
=> 1

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

Ответ 3

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

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

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