You can write a tail-recursive version of tokipin's code pretty easily. Personally though I think this could be an addition to the "examples of LOOP" thread from a while back.
(defun wrandf (xs weights)
(loop with r = (random (apply #'+ weights))
for x in xs
for w in weights
for cw = w then (+ cw w)
when (> cw r) return x))
; assumes pair
(defmacro wrand (&rest args)
`(funcall
(wrandf
(list ,@(mapcar (lambda (x) `(lambda () ,(cadr x))) (pair args)))
(list ,@(mapcar #'car (pair args))))))