Page 1 of 1

Passing Functions as Arguments

Posted: Tue Jun 14, 2011 9:28 am
by psholtz
How does one go about doing functional programming in Emacs Lisp?

They say that Lisp is a "functional" language, so you'd think it should be straightforward, but after googling around I've found comments from people to the effect that "functional programming in elisp is difficult to impossible"..

For instance, what I'm trying to do is something akin to:

Code: Select all

(defun f (x) (+ x 1))

(f 1)
;; 2

(defun x (y) (y 1))

(x f)
;; you could expect "2", but instead get a "void variable" error
The above idiom will work in Scheme or Python, but Emacs Lisp doesn't seem to like it.

Is there a way to pass functions as arguments in Emacs Lisp?

Re: Passing Functions as Arguments

Posted: Tue Jun 14, 2011 10:09 am
by Duke
psholtz wrote:They say that Lisp is a "functional" language, so you'd think it should be straightforward, but after googling around I've found comments from people to the effect that "functional programming in elisp is difficult to impossible"..
I was curious about this, so I did a little tinkering.

In your example, you need to use funcall.

Code: Select all

(defun f (x)
  (1+ x))

(defun x (y)
  (funcall y 1))

(x #'f)
The hashquote is shorthand for (FUNCTION f).

Higher order functions work. We can recurse, use predicates, and there seems to be no problem.

Code: Select all

(defun my-mapper (pred lst-a lst-b)
  (labels ((rec (a b acc)
                (if (and a b)
                    (rec (cdr a) (cdr b)
                         (cons (funcall pred (car a) (car b)) acc))
                  acc)))
    (rec lst-a lst-b nil)))

(my-mapper #'+ '(1 3 5 6) '(41 39 37 36))
...But is it doing proper tail-recursion?
Wikipedia wrote:Emacs Lisp (unlike some other Lisp implementations) does not do tail-call optimization.
:(

Can we do closures?

Code: Select all

(defun my-adder (x)
  (lexical-let ((var x))
    (lambda (n)
      (incf var n))))

(setq frobber (my-adder 8))
(funcall frobber 8) ;; => 16 24 32...
I think lexical-let was added only recently, but yes, that does seem to be a closure.

It may be that functional programming is "next to impossible" in Elisp just because of how heavy in side-effects Emacs programming is... I don't quite buy that, but the argument might hold water.

Anyway, I hope you found this informative. I certainly did. Not all Lisps are created equal, and there are certainly arguments to be made for an Emacs implemented in CL or Scheme. Something with support for threads.

A man can dream... ;)

Re: Passing Functions as Arguments

Posted: Tue Jun 14, 2011 10:13 am
by ramarren
psholtz wrote:They say that Lisp is a "functional" language
Lisp is not a language. Lisp is a family of very different languages using different paradigms. Emacs Lisp is not particularly functional. It does support some functional approaches, although since it uses dynamic bindings (there is a lexical-let in cl extension, but it is a hack) lexical closures are obviously impossible. Emacs Lisp is a fairly old dialect, predating Scheme, and mostly used an Emacs editor extension language.
psholtz wrote:Is there a way to pass functions as arguments in Emacs Lisp?
Emacs Lisp is a Lisp-2, which means it separates value space for values and functions. You can read about motivation for such separation in this paper. Symbols access appropriate namespace depending on their position. In operator position the function values is accessed and called, while in any other position value value is accessed.

In order to access a function without calling it you should use the special form FUNCTION. In order to call a function in value space, for example one passed as a function argument, bound to let, or created anonymously, you can use functions FUNCALL and APPLY. Refer about exact difference between them in Emacs built in help or Emacs Lisp manual. Your example can be written as:

Code: Select all

(defun f (x) (+ x 1))

(f 1)
;; 2

(defun x (y) (funcall y 1))

(x (function f))

Re: Passing Functions as Arguments

Posted: Sun Jun 19, 2011 12:05 am
by psholtz
Duke wrote:Anyway, I hope you found this informative. I certainly did. Not all Lisps are created equal, and there are certainly arguments to be made for an Emacs implemented in CL or Scheme. Something with support for threads.
I think there's an editor called "Hemlock" which purports to be an Emacs implemented in Common Lisp... although I haven't really played around w/ it.