Я пытаюсь понять, что является идиоматическим способом в Clojure для рекурсии через дерево или список, представленный списком Clojure (или другим типом коллекции).
Я мог бы написать следующее, чтобы подсчитать элементы в плоской коллекции (игнорируйте тот факт, что он не является хвостовым рекурсивным):
(defn length
([xs]
(if (nil? (seq xs))
0
(+ 1 (length (rest xs))))))
Теперь в схеме или CL все примеры только делают это над списками, поэтому идиотский базовый тест на этих языках будет (nil? xs)
. В Clojure мы хотели бы, чтобы эта функция работала над всеми типами коллекций, так же как идиоматический тест (nil? (seq xs))
, или, может быть, (empty? xs)
, или что-то совершенно другое?
Другим случаем, который я хотел бы рассмотреть, является обход дерева, т.е. перемещение по списку или вектору, который представляет дерево, например. [1 2 [3 4]
.
Например, подсчет узлов в дереве:
(defn node-count [tree]
(cond (not (coll? tree)) 1
(nil? (seq tree)) 0
:else (+ (node-count (first tree)) (node-count (rest tree)))))
Здесь мы используем (not (coll? tree))
для проверки атомов, тогда как в Схеме /CL мы будем использовать atom?
. Мы также используем (nil? (seq tree))
для проверки пустой коллекции. И, наконец, мы используем first
и rest
для разрушения текущего дерева левой ветки и остальной части дерева.
Итак, чтобы суммировать, следующие формы идиоматичны в Clojure:
-
(nil? (seq xs))
для проверки пустой коллекции -
(first xs)
и(rest xs)
для поиска в коллекции -
(not (coll? xs))
для проверки атомов