Просматривая записи Казимира Майорника, нашел у него очень любопытную статью. Это всего лишь забавный эксперимент, показывающий, как при помощи лисповой парадигмы "код-как-данные" можно реализовать циклическое выполнение кода без циклов и рекурсий. Никакой практической ценности в этом нет, просто красиво смотрится. Я написал что-то похожее на Clojure, но несколько усовершенствованное. В моей версии алгоритм выглядит так.
1) Список f содержит всего одну функцию. Её и запускаем первой.
2) Первая функция передает свой код в update.
3) Update "препарирует" код, находит номер текущей итерации, инкрементирует его и собирает такую же функцию, как ей передали, но с новым значением итерации.
4) Первая функция получает вторую функцию и добавляет её в конец списка f. Если список f содержит более трех элементов, то первый элемент списка f удаляется. Таким образом, в списке f содержится не более четырех элементов.
5) Первая функция запускает вторую функцию и завершается.
Выглядит и впрямь, как гусеничный трак :-)
1) Список f содержит всего одну функцию. Её и запускаем первой.
2) Первая функция передает свой код в update.
3) Update "препарирует" код, находит номер текущей итерации, инкрементирует его и собирает такую же функцию, как ей передали, но с новым значением итерации.
4) Первая функция получает вторую функцию и добавляет её в конец списка f. Если список f содержит более трех элементов, то первый элемент списка f удаляется. Таким образом, в списке f содержится не более четырех элементов.
5) Первая функция запускает вторую функцию и завершается.
Выглядит и впрямь, как гусеничный трак :-)
(defn update [func] (let [p (nth func 2) ;; Получить список (println (str "Hi for the " 1 " time!")) n (nth (second p) 2) ;; Получить 1 из списка ;; Создать список (println (str "Hi for the " 2 " time!")) new-p (cons 'println (list (map #(if (= n %) (inc n) (identity %)) (second p))))] ;; Заменить в теле функции (println (str "Hi for the " 1 " time!")) ;; на (println (str "Hi for the " 2 " time!")) (map #(if (and (seq? %) (= (first %) 'println)) new-p (identity %)) func))) (def f (ref ['(fn [] (println (str "Hi for the " 1 " time!")) (let [func (last @f) ;; Обновить список функций f ;; Удалить первую функцию, если список f содержит больше трех элементов new-f (if (> (count @f) 3) ;; Добавить обновленную функцию в конец списка (conj (vec (drop 1 @f)) (update func)) (conj @f (update func)))] (dosync (ref-set f new-f)) ;; Выполнить последнюю функцию списка ((eval (last @f)))))])) ((eval (last @f)))
Комментариев нет:
Отправить комментарий