Emacs Lispでvariance
Lispらしく書くならこんな感じ?
(defun varp-1 (xs) (cl-labels ((varp-sub (xs s1 s2 len) (if (consp xs) (let ((x (car xs))) (varp-sub (cdr xs) (+ s1 (* x x)) (+ s2 x) (1+ len))) (let ((e1 (/ s1 (float len))) (e2 (/ s2 (float len)))) (- e1 (* e2 e2)))))) (varp-sub xs 0 0 0)))
慣れないと読みづらいな。Python で書きなおすと、こう。
def varp_1(xs): def varp_sub(xs, s1, s2, length): if xs: x = xs[0] return varp_sub(xs[1:], s1 + x * x, s2 + x, length + 1) else: e1 = s1 / float(length) e2 = s2 / float(length) return e1 - e2 * e2 return varp_sub(xs, 0, 0, 0)
Emacs LispはTail Call Optimization効かないのでdolistマクロのが一般的かも。
(defun varp-2 (xs) (let ((s1 0) (s2 0) (len 0)) (progn (dolist (x xs) (progn (setq s1 (+ s1 (* x x))) (setq s2 (+ s2 x)) (setq len (1+ len)))) (let ((e1 (/ s1 (float len))) (e2 (/ s2 (float len)))) (- e1 (* e2 e2))))))
(benchmark-run 100 (varp-1 large-list)) (0.009979 0 0.0) (benchmark-run 100 (varp-2 large-list)) (0.00844 0 0.0)
dolistを使ったほうが少し早い。