Search code examples
elisp

Getting elisp to return a function as return value


I'm trying to create a function in elisp that returns another function. I looked at this answer to a similar question (how to return function in elisp) but did not understand the answer (I'm literally just starting learning elisp today, so please excuse my ignorance). I thought a simpler example would help. First, consider a function that test whether a number is divisible by 5:

(defun divisible-by-5 (x) 
  ;; tests whether a number is divsible by 5. 
  (setq remainder (% x 5))
  (if (= remainder 0) 1 0)
)

This works fine:

(divisible-by-5 25)
1

Now suppose I want to create a function that can create more of these kinds of test functions---something like:

(defun divisible-by-z (z)
  (lambda (z) 
  (setq remainder (% x z))
  (if (= remainder 0) 1 0))
 )

This does not work. E.g.,

(defun divisible-by-3 (divisible-by-z 3))
(divisible-by-3 4)

returns an error. I think even seeing an elisp-idiomatic example of how one would implement this pattern would be helpful.


Solution

  • First, make sure you have lexical-binding enabled. The simplest way to do so is to evaluate (setq lexical-binding t) in your current buffer. More information on the topic can be found here.

    Your definition of divisible-by-z is basically correct except that you have a mistype (naming both parameters z; the lambda's parameter should be x). Also, it would be more idiomatic to introduce the binding for remainder with let - setq is generally reserved for mutating bindings that already exist. Here's the result:

    (defun divisible-by-z (z)
      (lambda (x)
        (let ((remainder (% x z)))
          (if (= remainder 0) 1 0))))
    

    You can't use defun to create divisible-by-3 in quite the way you've tried - it's expecting the argument list for a new function to be where you have the call to divisible-by-z.

    You could either create a global, dynamic binding with

    (defvar divisible-by-3 (divisible-by-z 3))
    

    Or a local, lexical binding with

    (let ((divisible-by-3 (divisible-by-z 3)))
      ...)
    

    Either way, you'll then need to use funcall to call the function

    (funcall divisible-by-3 9) ; => 1
    

    Of course, you could also skip giving it its own name entirely and simply

    (funcall (divisible-by-z 3) 10) ; => 0
    

    funcall is necessary because Emacs Lisp is (basically) a Lisp-2, meaning it can attach both a function and a value to a given symbol. So when you're treating functions as values (returning one from a function or passing one in to a function as a parameter) you essentially have to tell it to look in that value "cell" rather than the usual function cell. If you search for "Lisp-1 vs Lisp-2" you'll find more than you want to know about this.