Page 1 of 1

Lisp Evaluation

Posted: Sun May 01, 2011 1:45 pm
by psholtz
I can use the following code in Scheme:

Code: Select all

(define (a-plus-abs-b a b)
 ((if (> b 0) + -) a b))
It basically looks at whether b is positive or not, and accordingly selects the "+" or "-" operation to apply to the arguments a and b.

It runs fine in Scheme:

Code: Select all

(a-plus-abs-b 1 1) 
;; 2

(a-plus-abs-b 1 -1)
;; 2
However, when I try to define the same procedure in Emacs Lisp, the code crashes:

Code: Select all

(defun a-plus-abs-b (a b)
 ((if (> b 0) + -) a b))
Why is this?

Does Emacs Lisp evaluate expressions in a different manner than Scheme?

Re: Lisp Evaluation

Posted: Sun May 01, 2011 11:47 pm
by ramarren
psholtz wrote:Does Emacs Lisp evaluate expressions in a different manner than Scheme?
Lisp is a family of very varied languages and you should generally not expect more than surface similarities. Emacs Lisp is a Lisp-2 with dynamic binding and focus on side-effects, and so very different from Scheme. It would be likely most effective to learn Emacs Lisp from scratch (documentation) rather than trying to adapt any Scheme knowledge.

To answer the direct question: in Lisp-2, like Common Lisp and Emacs Lisp, there is a separate namespace for operators. The operator position of a form must be a name in that namespace, which is either a symbol naming a function or a lambda form. All other forms are an error.

Re: Lisp Evaluation

Posted: Wed May 04, 2011 8:11 pm
by nuntius
In a lisp-2, the idiomatic form is

Code: Select all

(defun a-plus-abs-b (a b)
  (if (> b 0)
    (+ a b)
    (- a b)))
or maybe

Code: Select all

(defun a-plus-abs-b (a b)
  (+ a (if (> b 0) b (- b)))) ; explicit (abs b)
The literal translation of your code is

Code: Select all

(defun a-plus-abs-b (a b)
  (funcall (if (> b 0) '+ '-) a b))

Re: Lisp Evaluation

Posted: Sat Jun 04, 2011 7:21 am
by findinglisp
To give a bit longer answer, there is a notion in the Lisp family of languages of Lisp-1 vs. Lisp-2. In a Lisp-1 variant (e.g., Scheme), symbols have only a single value. If you see the symbol LIST, for instance, it's always bound to the same thing. This is true whether the symbol appears in the first position of a function call form or anyplace else. In a Lisp-2 variant (e.g., Common Lisp, Emacs Lisp), the symbol LIST can evaluate to two different values depending on where it appears. As the first symbol in a function call, it evaluates to the function associated with the symbol. In any other position, it evaluates to the data value associated with the symbol. This is convenient, because it allows you to have variable names that would otherwise clash with the names of functions. For instance:

Code: Select all

(defun foo (list)    ; LIST is a variable here, no conflict with the LIST function
    (list 'a list))  ; First LIST is a call to the LIST function. Second LIST is a reference to the LIST variable.
If you want to access the function associated with a symbol when the reference would otherwise select the data, preface the symbol with pound-tick: #'SYMBOL.

Re: Lisp Evaluation

Posted: Sun Aug 19, 2012 12:56 am
by spacebat
Good explanation, but there's a minor distinction when it comes to emacs lisp that one doesn't notice much in typical use.
findinglisp wrote:If you want to access the function associated with a symbol when the reference would otherwise select the data, preface the symbol with pound-tick: #'SYMBOL.
That's true for common lisp, but only at compile time for emacs lisp. In both cases #'x acts like (function x).

In emacs lisp, (function x) is just like (quote x) except at compile time, when it indicates that x should be compiled. This matters when the argument x is a lambda expression. For compatibility, forms like funcall and apply that expect a function argument will also happily accept a symbol and get the function object to call from its function slot.

Code: Select all

ELISP> (defun add (a b) (+ a b))
add
ELISP> #'add
add
ELISP> 'add
add
ELISP> (function add) ;; acts like (quote add) except at compile time
add
ELISP> (symbol-function 'add) ;; gives the actual function object from the function slot of the symbol
(lambda
  (a b)
  (+ a b))
ELISP> (funcall #'add 2 3) ;; funcall gets the add symbol and pulls out the function
5
ELISP> (funcall 'add 2 3) ;; ditto
5
ELISP> (funcall (function add) 2 3) ;; ditto
5
ELISP> (funcall (symbol-function 'add) 2 3) ;; funcall is passed the actual function object
5