Если вы изучаете Clojure, скорее всего, это не ваш первый язык. Итак, вы, вероятно, немного знакомы с тем, что такое рекурсия.

Мы начнем с создания простой факториальной функции, чтобы начать видеть рекурсию.

(defn factorial [n] ;; our factorial function accepting one argument (if (= n 1) ;; checks if n is equal to 1 and if so returns 1
1
(* n (factorial (dec n))))) ;; calls the factorial again after decreasing n by 1.

Хорошо, давайте посмотрим, работает ли это, выполнив тест.

(factorial 3) ;; which we know should be 3x2x1 which is 6. So it works. ;; 6

Итак, давайте проверим мощность нашей функции, выполнив что-то большее, например 40.

(factorial 40) ;; Oh no a StackOverError. What happened?

Так что наша функция не так велика, как мы думаем. Он не будет принимать большие числа.

(defn factorial [n] ;; Our factorial function accepts one argument. (loop [n n ;; This is the looping part which sets our argument to n sum 1] ;; Our sum is just one for now. 
(if (= n 0) ;; If n becomes 0 than return the sum basically ends the loop 
sum (recur (dec n) (* sum n))))) ;; This will continue the loop til the if state is met.

Использование recur гарантирует, что вы не столкнетесь с StackOverError, например, функция до этого не использовала преимущества recur и, таким образом, не была оптимизирована по принципу «голова-хвост». Clojure выполнит оптимизацию на основе вызова конца, если вы используете функцию recur. Кроме того, если вы используете эту функцию сейчас, она выдаст вам StackOverError, но поскольку вам нужно установить JVM, используя -Xss и -XThreadStackSize, чтобы установить размер стека, иначе вы все равно получите эту ошибку для чисел больше 20.

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

(defn factorial [n] (reduce * (range 1 (inc n)))) ;; Takes advantage of range making a list of numbers.

Второй использует диапазон, поскольку он создает список чисел, а затем умножает все числа, которые создает диапазон.

Первоначально опубликовано на defunsm.github.io.