Passing Functions as Arguments

Discussion of Emacs Lisp

Passing Functions as Arguments

Postby psholtz » Tue Jun 14, 2011 9:28 am

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?
psholtz
 
Posts: 5
Joined: Sun May 01, 2011 1:41 pm

Re: Passing Functions as Arguments

Postby Duke » Tue Jun 14, 2011 10:09 am

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... ;)
Last edited by Duke on Tue Jun 14, 2011 11:41 am, edited 1 time in total.
"If you want to improve, be content to be thought foolish and stupid." -Epictetus
Duke
 
Posts: 38
Joined: Sat Oct 17, 2009 10:40 pm

Re: Passing Functions as Arguments

Postby Ramarren » Tue Jun 14, 2011 10:13 am

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))
Ramarren
 
Posts: 613
Joined: Sun Jun 29, 2008 4:02 am
Location: Warsaw, Poland

Re: Passing Functions as Arguments

Postby psholtz » Sun Jun 19, 2011 12:05 am

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.
psholtz
 
Posts: 5
Joined: Sun May 01, 2011 1:41 pm


Return to Emacs Lisp

Who is online

Users browsing this forum: No registered users and 0 guests

cron