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を使ったほうが少し早い。