Git Product home page Git Product logo

emacs-memoize's Introduction

Elisp memoization functions

See the header in the source file for details. It's very easy to use:

(require 'memoize)

(memoize 'my-function)

The macro defmemoize is also provided to directly create memoized functions:

(defmemoize my-expensive-function (n)
  (if (zerop n)
      1
    (* n (my-expensive-function (1- n)))))

Some functions are run over buffer contents, and need to be cached only so long as the buffer contents do not change. For these use-cases, we have the function memoize-by-buffer-contents as well as the defmemoize-by-buffer-contents macro.

To restore the original definition of a memoized function symbol (not a lambda or closure), use memoize-restore:

(memoize 'my-function)
(memoize-restore 'my-function)

emacs-memoize's People

Contributors

ahyatt avatar alphapapa avatar cireu avatar damiencassou avatar rolpereira avatar skeeto avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

emacs-memoize's Issues

Persistent memoization

Is there a way to have Emacs persist the cache between sessions, by saving and restoring the cache to the filesystem?

Throttle?

Hi again Chris,

I was browsing the CL Serapeum library and came across its throttle function. It seems complementary to memoize. I have a function in my Emacs config that I would like to throttle (it plays a notification sound when I get messages in matrix-client; I add it as advice to the built-in notification function), and it seems like this would be a good way to do it. What do you think?

(defun throttle (func interval)
  "Throttle FUNC: a closure, lambda, or symbol.

If argument is a symbol then install the throttled function over
the original function.  INTERVAL, a number of seconds or a
duration string as used by `timer-duration', determines how much
time must pass before FUNC will be allowed to run again."
  (cl-typecase func
    (symbol
     (when (get func :throttle-original-function)
       (user-error "%s is already throttled" func))
     (put func :throttle-original-documentation (documentation func))
     (put func 'function-documentation
          (concat (documentation func) " (throttled)"))
     (put func :throttle-original-function (symbol-function func))
     (fset func (throttle--wrap (symbol-function func) interval))
     func)
    (function (throttle--wrap func interval))))

(defun throttle--wrap (func interval)
  "Return the throttled version of FUNC.
INTERVAL, a number of seconds or a duration string as used by
`timer-duration', determines how much time must pass before FUNC
will be allowed to run again."
  (let ((interval (cl-typecase interval
                    ;; Convert interval to seconds
                    (float interval)
                    (integer interval)
                    (string (timer-duration interval))
                    (t (user-error "Invalid interval: %s" interval))))
        last-run-time)
    (lambda (&rest args)
      (when (or (null last-run-time)
                (>= (float-time (time-subtract (current-time) last-run-time))
                    interval))
        (setq last-run-time (current-time))
        (apply func args)))))

Optional keywords (e.g. `timeout`) for the `defmemoize` macro

May I suggest to add the following boilerplate to the defmemoize macro:

(defmacro defmemoize (name arglist &rest body)
  "Create a memoize'd function.
NAME, ARGLIST, DOCSTRING and BODY have the same meaning as in `defun'."
  (declare (indent 2) (doc-string 3) (debug defun))
  (let (doc-form doc-string keyword-plist)
    (when (> (length body) 1)
      (if (eq (car-safe (car-safe body)) 'format)
          (setq doc-form (pop body))
        (when (stringp (car-safe body))
          (setq doc-string (pop body)))))
    (while (keywordp (car-safe body))
      (setq keyword-plist (plist-put keyword-plist (pop body) (pop body))))
    (when (and body (consp (car body)) (eq (caar body) 'interactive))
      (user-error "Memoizing interactive function (`%s') is discouraged" name))
    `(progn
       (defun ,name ,arglist
         ,@(when doc-string `(,doc-string))
         ,@body)
       ,(when doc-form
          `(put (quote ,name) 'function-documentation ,doc-form))
       (memoize (quote ,name) (plist-get keyword-plist :timeout)))))
  1. Documentation string and form parsing and handling;
  2. Optional keywords (e.g. timeout) parsing and handling;
  3. Error upon attempt to memoize an interactive function at compile time (maybe worth moving that piece to memoize function itself, so I leave this one up to you).

Mainly, one could now do:

(defmemoize foo (bar &optional baz)
  "..."
  :timeout "7 hours"
  ...)

Thanks and cheers!

`defmemoize` has wrong `indent` for argument list

Try to wrap argument list to the next line like this

(defmemoize foo
  (&optional xxx)
  "..."
  ...)

and you will see that, after indentation, instead of 4 spaces, the argument list is only indented by 2.

tagged release

Is it possible to get a 1.0.1 tag? That way this could appear in MELPA Stable. Thanks!

De-memoize function?

Hi Chris,

What do you think about adding a function to de-memoize memoized functions? I'm thinking about using memoize with magit-todos to cache a magit function call, but I'd like to only do that when the minor mode is activated, and then de-memoize it when the mode is deactivated, so as not to permanently interfere with magit.

Redefining a function created with defmemoize disables memoization

For example, with the function

(defmemoize f (x)
  (sit-for 1)
  (* x x))

(f 3)
(f 3)

The first call (f 3) takes 1 second and the next one is instant as expected. However, if one evaluates the code above and then evaluates it again a second time, both (f 3) calls take one second. This shows that memoization is not working after f has been redefined. This is easy to fix and I will submit a pull request in a moment.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.