Theorically, LET initialization expressions could be evaluated in
parallel, but they can still have dependencies if they have side
effects, that would prevent parallelizing them. In any case, it's very
fine grained parallelism (at the level of simple expressions, (all
right, you might also call big functions, but with big functions come
big side effects and therefore less possibility of parallelizing
evaluation).
So in practice,
(shadow 'let)
(defmacro let (bindings &body body)
`((lambda ,(mapcar (lambda (binding)
(if (atom binding) binding (first binding)))
bindings)
,@body)
,@(mapcar (lambda (binding)
(if (atom binding) 'nil (second binding)))
bindings)))
(macroexpand '(let ((a (incf i)) (b (incf i)) (c (incf i))) (list a b c))
--> ((lambda (a b c) (list a b c)) (incf i) (incf i) (incf i))
Now, for let*:
(shadown 'let*)
(defmacro let* (bindings &body body)
(if (null bindings)
`(progn ,@body)
`((lambda (,(if (atom (car bindings)) (car bindings) (caar bindings)))
(let* ,(cdr bindings) ,@body))
,(if (atom (car bindings)) 'nil (cadar bindings)))))
(ext:expand-form '(let* ((a 0) (b (1+ a)) (c (1+ b))) (list a b c)))
--> ((LAMBDA (A) ((LAMBDA (B) ((LAMBDA (C) (LIST A B C)) (1+ B))) (1+ A))) 0)
As for which one is faster, see for yourself, try to write forms
evaluating the same things, differing only in let vs. let*:
C/USER[12]> (disassemble (compile nil (lambda (a b) (let ((a 0) (b (1+ a)) (c (1+ b))) (list a b c)))))
Disassembly of function NIL
(CONST 0) = 0
2 required arguments
0 optional arguments
No rest parameter
No keyword parameters
7 byte-code instructions:
0 (LOAD&INC&PUSH 2)
2 (LOAD&INC&PUSH 2)
4 (CONST&PUSH 0) ; 0
5 (LOAD&PUSH 2)
6 (LOAD&PUSH 2)
7 (LIST 3)
9 (SKIP&RET 5)
NIL
C/USER[13]> (disassemble (compile nil (lambda () (let* ((a 0) (b (1+ a)) (c (1+ b))) (list a b c)))))
Disassembly of function NIL
(CONST 0) = 0
0 required arguments
0 optional arguments
No rest parameter
No keyword parameters
8 byte-code instructions:
0 (CONST&PUSH 0) ; 0
1 (CALLS2&PUSH 177) ; 1+
3 (LOAD&INC&PUSH 0)
5 (CONST&PUSH 0) ; 0
6 (LOAD&PUSH 2)
7 (LOAD&PUSH 2)
8 (LIST 3)
10 (SKIP&RET 3)
NIL
C/USER[14]>
--
__Pascal Bourguignon__
http://www.informatimago.com/
A bad day in () is better than a good day in {}.