lambda seems to have an "inherent"
progn as well, such that
(funcall (lambda (x y z) A B C) 1 2 3) is equivalent to
(let ((x 1) (y 2) (z 3)) A B C).
"Equivalent" is a strong word. Calling a
lambda with a set of arguments may have a similar effect to evaluating the
lambda's body with the appropriate
let bindings in place, but their corresponding semantics are quite different.
a) What are the identifies between
Are you asking how they relate/compare to one another?
progn is pure sequential evaluation of Lisp forms
let is the same but with local variable binding at the start and unbinding at the end
lambda evaluates to an anonymous function under dynamic binding, and
a closure under
how would you implement
progn just using
That depends on what you mean by "implement using
let". You can't use
let alone to define a function, macro, or special form that will do the same thing as either
progn, but some rewriting is possible in the case of
;; Expressions of this form:
;; can generally be written as:
(let () BODY...)
No such rewrite is possible for anonymous functions and closures in general, because their evaluation semantics and byte-compilation are quite different to those of
;; For example, this expression:
(lambda (x) (1+ x))
;; is not, under dynamic binding, the same as:
(list 'lambda '(x) '(1+ x))
;; and not, under lexical binding, the same as:
(list 'closure '(t) '(x) '(+ x y))
(progn (progn (A) (B) (C))) always equivalent to
(progn ((A) (B) (C)))?
No, those two forms are never equivalent.
(progn (progn (A) (B) (C))) is valid Elisp which evaluates
(C) in that order, and returns the result of evaluating
(progn ((A) (B) (C))) is valid if and only if
(A) is a valid
(lambda ...) expression, as the first element of an evaluated list must already be (not evaluate to) a valid function object. In that case,
(C) are evaluated and passed as arguments to the anonymous function/closure
(A), whose result is then returned by
(I have the faint impression that expressions of the form
((lambda ...)) are meant to eventually be outlawed in Elisp, but I'm not sure.)
Update from Comments
In asking b), I meant to ask about the semantics and evaluation of the "implicit"
lambda and an explicit
progn in their body, i.e. how does
(let () (progn BODY...)) work?
(let () (progn BODY...)) is effectively the same as
(progn (progn BODY...)), which is effectively the same as
(progn BODY...), i.e. adding an explicit
progn where there is already an implicit one is practically redundant/idempotent.
The special form
let is actually implemented in terms of
DEFUN ("let", Flet, Slet, 1, UNEVALLED, 0,
doc: /* Bind variables according to VARLIST then eval BODY.
The value of the last form in BODY is returned.
Each element of VARLIST is a symbol (which is bound to nil)
or a list (SYMBOL VALUEFORM) (which binds SYMBOL to the value of VALUEFORM).
All the VALUEFORMs are evalled before any symbols are bound.
usage: (let VARLIST BODY...) */)
/* Bind local variables according to first argument. */
Lisp_Object varlist = XCAR (args);
ptrdiff_t count = SPECPDL_INDEX ();
/* ...magic happens here... */
/* Pass remaining arguments to 'progn'. */
Lisp_Object elt = Fprogn (XCDR (args));
/* Unbind local variables; return result of 'progn'. */
return SAFE_FREE_UNBIND_TO (count, elt);
Note that idiomatic Elisp avoids redundant nesting of
progn where possible.