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

#clojure

#clojure

Вопрос:

Есть ли в Clojure макрос считывателя или основная функция, которая похожа на recur , но возможна с положением без хвоста?

Например, в этой рекурсивной функции

 (defn insertR* [newkey oldkey l]
  (cond
    (empty? l)  '()
    (not (seq? (first l)))
        (if (= (first l) oldkey)
        (cons oldkey (cons newkey (insertR* newkey oldkey (rest l))))
        (cons (first l) (insertR* newkey oldkey (rest l))))    
    :else
        (cons (insertR* newkey oldkey (first l)) (insertR* newkey oldkey (rest l)))))
  

Есть ли какая-нибудь универсальная функция, которую я могу использовать для вызова самой себя вместо insertR* явного вызова?

Ответ №1:

Ваш вопрос неясен. Если вы имеете в виду: могу ли я сделать это без использования пространства стека? Нет. У вашего insertR* есть несколько самостоятельных вызовов, и это невозможно выразить без стека.

Если вы имеете в виду: могу ли я использовать слово типа recur для обозначения «Вызывайте себя рекурсивно», и мне все равно, использует ли оно stack? Не совсем. Впрочем, вы могли бы написать ее самостоятельно. Что-то вроде:

 (defmacro defrec [name amp; fntail]
  `(def ~name (fn ~'recurse ~@fntail)))

(defrec foo [x]
  (when-not (zero? x)
    (recurse (dec x))))
  

Я подозреваю, что в этом есть несколько пробелов, но в основном это делает то, о чем вы думаете.

Ответ №2:

Зачем вам такая функция / макрос? recur создан для оптимизации конечных вызовов. Кажется, что ваша функция этого не допускает (возможно, я ошибаюсь). Хотя вы сказали, что вам это не нужно. Почему вы хотите явно заменить ваш вызывающий insertR * на что-то другое? Если вам не нравится каждый раз передавать newkey oldkey (а они не изменены), вы можете создать внутреннюю функцию, которая будет использовать эти ключи.

Комментарии:

1. Просто чтобы я мог выделить рекурсивные вызовы в моей IDE с использованием универсального ключевого слова