1
votes

I'm reading the r6rs(Revised6 Report on the Algorithmic Language Scheme), in the "INTRODUCTION" part there is one summary:

"Scheme was the first major dialect of Lisp to distinguish procedures from lambda expressions and symbols, to use a single lexical environment for all variables, and to evaluate the operator position of a procedure call in the same way as an operand position."

My questions are:

what's the benefit of "to distinguish procedures from lambda expressions and symbols"?

what's the single lexical environment? my understanding is, because of the lexical scope, everything in Scheme are "lexical", no run-time scope there, location/position in the source code means more about the environment.

how to understand "to evaluate the operator position of a procedure call in the same way as an operand position"? my understanding is the symbol at operator position is evaluated as operand position. for example:

(define test
    (lambda (x)
        ((if (> x 0) + -) 1 2)))

the "(if (> x 0) + -)" is at the operator position, its evaluation is same as other operand position's evaluation.

2
These statements make more sense if you have a passing familiarity with other Lisps, like Common Lisp.molbdnilo

2 Answers

2
votes

Scheme was the fist Lisp to have lexcical environments and closures. It affected the design of Common Lisp quite a bit. The alternative to lexical environment is dynamic bindings. Example:

;; setup (on both)
(define v 10)

(define (adder v)
  (lambda (x) (+ x v))))

;; lexical scheme results
(define add5 (adder 5))
(add5 3) ; ==> 8
(let ((v 6))
  (add5 3)) ; ==> 8

;; dynamic scheme results
(define add5 (adder 5))
(add5 3) ; ==> 13 (since y is the global variable 10)
(let ((v 6))
  (add5 3)) ; ==> 9 (since v is bound to 6 during the call to add5)

Scheme doesn't have dynamic variables so the last part won't happen. Common Lisp actually has dynamic scope for global defined variables so if you can actually test this in CL:

(defparameter *v* 10)
(defparameter *x* 0)

(defun adder (*v*)
  (lambda (*x*) (+ *x* *v*))))

;; lexical scheme results
(defparameter *add5* (adder 5))
(funcall *add5* 3)    ; ==> 13
(let ((*v* 6))
  (funcall *add5* 3)) ; ==> 9

There are lisp dialects that only have dynamic binding. picoLisp and early versions of elisp are examples.

Notice that Common Lisp uses funcall since I have bound a function to a variable. That is because they have two namespaces. One for evaluating forms in the operator position and one for the rest. Thus in CL you can have the function list and the argument named list and they are different values. Below is code that will not work in Scheme but work perfectly fine in CL:

(let ((list '(1 2 3)))
  (list list list))

; ==> ((1 2 3) (1 2 3)) in CL
; ==> Application: (1 2 3) is not a procedure error in Scheme
1
votes

what's the single lexical environment?

Well, Scheme has a single lexical environment, but older lisps can have more than one lexical environment. If for example you maintain separate environments for function (names) and argument (names), then you can write:

> (define (foo foo) (+ foo 3))
> (foo 4)
7

"to evaluate the operator position of a procedure call in the same way as an operand position"?

When you have one environment for functions and another for arguments, procedure calls use the function argument to lookup the operator, and the other environment for the arguments.

See also this answer (by none other than Kent Pittman) and follow the link to the paper on lisp-1 vs lisp-2.

Is "Lisp-1 vs Lisp-2" relevant in a language with static types?