;;AUTOLOAD: let*
;;AUTODOC: let* "local declaration of variables, sequential"
;;(let* (var-inits...) forms...)
;;
;;Where var-inits is either variable-name or (variable-name init-value)
;;let* assigns sequentially:
;;(let* ((x 1) (y x)) y) will return 1
;;(let  ((x 1) (y x)) y) will return the value of x before entering the let
;;WARNING: let* is slower than with, which is 
;;slower than the &aux declaration of local variables in functions

(defmacrod let* (let:vars &rest let:forms &aux
  )
  `(with ,(let*:expand-args let:vars) ,@let:forms)
)

(defun let*:expand-args (args &aux
    (res (copy ()))
  )
  (dolist (var args)
    (if (typep var List)
      (progn
	(lappend res (getn var 0))
	(lappend res (getn var 1))
      )
      (progn
	(lappend res var)
	(lappend res ())
      )
  ))
  res
)

;;AUTOLOAD: let
;;AUTODOC: let "local declaration of variables, in parallel"
;;(let (var-inits...) forms...)
;;
;;Where var-inits is either variable-name or (variable-name init-value)
;;let assigns in parallel:
;;(let* ((x 1) (y x)) y) will return 1
;;(let  ((x 1) (y x)) y) will return the value of x before entering the let
;;thus to exchange the values of x and y, say (let ((x y) (y x)) ...)
;;WARNING: let is MUCH slower than let*, which is slower than with, which is 
;;slower than the &aux declaration of local variables in functions

(defmacrod let (let:vars &rest let:forms &aux
  )
  `(with ,(let:expand-args let:vars) ,@let:forms)
)

(defvar let:prefix_gensym "#let:tmp:")

(defun let:expand-args (args &aux
    (old (copy ()))
    (new (copy ()))
    (num 0)
    name
    var
    val
  )
  (dolist (arg args)
    (if (typep arg List)
      (setqn var (getn arg 0) val (getn arg 1))
      (setqn var arg val ())
    )
    (setq name (intern (+ let:prefix_gensym (String (incf num)))))
    (lappend old name)
    (lappend old val)
    (lappend new var)
    (lappend new name)
  )
  (+ old new)
)
