Приятно видеть, что так много людей изучают Clojure на этой неделе :) начинать с фундаментальной проблемы, как это действительно хорошее начало. Ответы Хамзы и Йонаса четко охватывают исходный вопрос. Я хотел бы предложить несколько незапрошенных советов о том, где взять его отсюда, в надежде, что это будет полезно.
Получив базовую рекурсивную форму, вы можете превратить ее в идиоматическое Clojure, как правило:
1) используйте хвостовые рекурсивные формы, когда можете (вы уже это сделали)
2) замените прямую рекурсию на вызов recur
, чтобы избежать перебора стека. (начиная с рабочего ответа Хамзы)
(defn my-even? [coll]
(if-let [[first & rest] coll]
(if (= (mod first 2) 0)
(cons first (my-even? rest))
(recur rest))))
recur
заставляет компилятор переходить к началу кадра стека вместо выделения нового. без этого он взорвется в стеке.
3) во многих случаях вы можете исключить шаблон (defn [] ... (recur))
с помощью функции более высокого порядка, например map
, reduce
, filter
, for
и т. Д. В этом упражнении я вижу, что вы пытаетесь не используйте filter
или even
, так что, очевидно, вы могли бы написать my-filter и my-even, и это было бы нормально;)
4) извлекает делимые части (строит список, выбирает, что включить) в повторно используемые функции и загружает любые, которые обычно полезны для проекта contrib clojure:)
5) очень внимательно подумайте, если вы обнаружите, что используете (lazy-seq ...)
, поскольку есть большая вероятность, что вы заново изобретаете колесо.