LINUX.ORG.RU

[lisp] Мемоизация

 


0

0

Играюсь с лиспом, возник такой вопрос: есть функция g, которая вызывает мемоизованую функцию f, причем f используется только внутри g и нигде больше, но для этого f приходится объявлять вне g, а это не очень красиво смотрится.

(def f (memoize (fn [x] ...)))

(defn g [y]
...
(f y)
...)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Так вот, есть ли какой способ объявить мемоизованную f внутри g так, чтобы кэш мемоизации f не сбрасывался при повторном вызове g?

(defn g [y]
...
(with-memo [f (fn [x] ...)] ;;;; Что-нибудь на подобие этого :)
(f y))
...)

Что-то мне кажется что это не CL а Clojure.
Если я прав, то прямо из Programming Clojure пример:
(use 'clojure.contrib.memoize)
(defn demo-memoize []
(time
(dorun
(binding [slow-double (memoize slow-double)]
(calls-slow-double)))))


Svoloch ★★★
()

Говоря "лисп" лисперы подразумевают либо все семейство языков, начиная с Emacs Lisp и заканчивая Arc, либо Common Lisp.
Твой пост - о мутных деталях реализации встроенной мемоизации в Clojure, а не о лиспе.

guest-3484-2009
()
Ответ на: комментарий от guest-3484-2009

> Твой пост - о мутных деталях реализации встроенной мемоизации в Clojure, а не о лиспе.

Не совсем так. Я смотрел как реализована мемоизация в Clojure в исходниках самого Clojure и как в Common Lisp'е в PAIP - вся разница между ними в синтаксическом сахаре.

zahardzhan
() автор топика
Ответ на: комментарий от zahardzhan

Ну, на CL можно так:

(defun memoize (fn &key (key-fn #'first) (test #'eql))
  (let ((hash (make-hash-table :test test)))
    #'(lambda (&rest args)
        (let ((key (funcall key-fn args)))
          (multiple-value-bind (value value-p) (gethash key hash)
            (if value-p
                value
                (setf (gethash key hash) (apply fn args))))))))

(defmacro memoized-flet ((&rest fn-spec*) &body body)
  (multiple-value-bind (var-def fn-def) 
      (loop for spec in fn-spec*
         for memo-var = (gensym)
         for args-var = (gensym)
         for name = (first spec)
         for args = (second spec)
         for fn-body = (cddr spec)
         collect `(,memo-var (memoize #'(lambda ,args ,@fn-body))) into let-block
         collect `(,name (&rest ,args-var)
                         (apply ,memo-var ,args-var)) into flet-block
         finally (return (values let-block flet-block)))
    `(let ,var-def
       (flet ,fn-def
         ,@body))))

Использовать как-то так:

(defun g (...)
  (memoized-flet ((f (...)
                     ...))
    ...))

если использовать cl-utilities будет красивее.

Sectoid ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.