В духе обучения:
Вы можете использовать &
или нет.Оба в порядке.Разница заключается в том, как бы вы тогда вызывали свою функцию, и вам нужно было бы не забывать использовать apply
при повторении.
Также просто используйте first
и rest
.Они оба безопасны и будут работать как с нулевым, так и с пустым списками, возвращая ноль и пустой список соответственно:
(first []) ;; -> nil
(first nil) ;; -> nil
(rest []) ;; -> ()
(rest nil) ;; -> ()
Итак, вот как я бы переработал вашу идею:
;; With '&'
(defn count-a [& lst]
(if-let [a (first lst)]
(+ (if (= a "a") 1 0)
(apply count-a (rest lst))) ;; use 'apply' here
0))
;; call with variable args, *not* a list
(count-a "a" "b" "a" "c")
;; Without '&'
(defn count-a [lst]
(if-let [a (first lst)]
(+ (if (= a "a") 1 0)
(count-a (rest lst)))
0))
;; call with a single arg: a vector (could be a list or other )
(count-a ["a" "b" "a" "c"])
Однако это небезопасно, потому что они не используют хвостовую рекурсию, и поэтому, если ваш список большой, вы взорвете свой стек!
Итак, мы используем recur
.Но если вы не хотите определять дополнительную «вспомогательную» функцию, вы можете вместо этого использовать loop
в качестве «повторяющейся» цели:
;; With '&'
(defn count-a [& lst]
(loop [c 0 lst lst] ;; 'recur' will loop back to this point
(if-let [a (first lst)]
(recur (if (= a "a") (inc c) c) (rest lst))
c)))
(count-a "a" "b" "a" "c")
;; Without '&'
(defn count-a [lst]
(loop [c 0 lst lst]
(if-let [a (first lst)]
(recur (if (= a "a") (inc c) c) (rest lst))
c)))
(count-a ["a" "b" "a" "c"])
Все это, как я сказал, тожебудет использовать:
;; With '&'
(defn count-a [& lst]
(count (filter #(= % "a") lst)))
(count-a "a" "b" "a" "c")
;; Without '&'
(defn count-a [lst]
(count (filter #(= % "a") lst)))
(count-a ["a" "b" "a" "c"])