John Horton
John Horton

Reputation: 4282

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.

Upvotes: 1

Views: 1084

Answers (3)

dardisco
dardisco

Reputation: 5274

Another (perhaps simpler) method is to include x as a variable to be passed to the function:

(defun divisible-by-z (x z) "
Check if x is divisible by z.
If so, return 0.
If not, return the remainder."
   (if (% x z) (% x z) 0))

thus:

(divisible-by-z 5 2) --> 1
(divisible-by-z 4 2) --> 0

Upvotes: 0

jbm
jbm

Reputation: 2600

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.

Upvotes: 4

jlahd
jlahd

Reputation: 6293

A possible solution:

(defun divisible-by-3 (x)
  (funcall (divisible-by-z 3) x))

Upvotes: 3

Related Questions