# let : let* :: do : do*

```first a minor issue:
Both list-tail and list-ref specify that the first argument should be
a list.  But in neither case does the argument need to be non-circular.
---------------
DO* is defined in common-lisp and is related to DO as LET* is related
to LET.  Its inclusion in scheme would make the function set more
orthogonal.

My main reason for recommending that DO* be included in the Scheme
language is that mathematical algorithms are usually expressed in
pseudo-Algol which translates to the constructs LET* and DO*.  A LET*
in the body of a DO does not do the job because only the variables in
the outer DO are available for the test clause.

I am writing a symbolic mathematics system in Revised^3.99 Scheme.
The code is more than 4000 lines long.  I find that squeezing the
loops into DO (without DO*) is difficult and leads to contorted
arrangements for the <init> and <test> clauses to make them look ahead.

Here is my code for computing the subdeterminant Psuedo Remainder
Sequence of two polynomials.

;;; This algorithm taken from:
;;; Knuth, D. E.,
;;; The Art Of Computer Programming, Vol. 2: Seminumerical Algorithms,

;;; Pseudo Remainder Sequence
(define (univ_prs u v)
(let ((var (car u))
(g 1)
(h 1)
(delta 1))
(do ((r (univ_prem u v) (univ_prem u v)))
((eqv? 0 (univ_degree r var))
(if (eqv? 0 r) v r))
(set! delta (- (univ_degree u var) (univ_degree v var)))
(set! u v)
(set! v (poly_/ r (poly_* g (poly_^ h delta))))
(set! g (car (last-pair u)))
(set! h (cond ((one? delta) g)
((zero? delta) h)
(else (poly_/ (poly_^ g delta)
(poly_^ h (+ -1 delta)))))))))

;Here would be the code with DO*
(define (univ_prs u v)
(do* ((var (car u))
(delta 0 (- (univ_degree u var) (univ_degree v var)))
(u u v)
(v v (poly_/ r (poly_* g (poly_^ h delta))))
(g 0 (car (last-pair u)))
(h 0 (cond ((one? delta) g)
((zero? delta) h)
(else (poly_/ (poly_^ g delta)
(poly_^ h (+ -1 delta))))))
(r (univ_prem u v) (univ_prem u v)))
((eqv? 0 (univ_degree r var))
(if (eqv? 0 r) v r))))

```

• Follow-Ups: