memo pythonでの部分適用

functools.partialの存在意義が分からなかった。
lambdaで包んで返せばそれで良いと思っていた。
勘違いしていた。
確かに、functools.partialは便利だ。

def f(x):
    def _f():
        return x + 1
    return _f

xs = [f(x) for x in xrange(10)]
print [x() for x in xs]

g = lambda x : lambda : x + 1
ys = [g(x) for x in xrange(10)]
print [y() for y in ys]

zs = [lambda : x  + 1 for x in xrange(10)]
print [z() for z in zs]

# [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# [10, 10, 10, 10, 10, 10, 10, 10, 10, 10]

scheme(schemeっぽくないけど)

(let1 r '()
  (let1 xs (iota 10)
    (while (not (null? xs))
      (push! r (lambda () (or (null? xs) (+ (car xs) 1))))
      (pop! xs)))
  (map (lambda (f) (f)) r)) ; => (#t #t #t #t #t #t #t #t #t #t)

;; 間違い
;; (let1 r '()
;;   (let1 xs (iota 10)
;;     (while (not (null? xs))
;;       (push! r (lambda () (+ (car xs) 1)))
;;       (pop! xs)))
;;   (map (lambda (f) (f)) xs)) ; => (10 9 8 7 6 5 4 3 2 1)

(let1 r '()
  (let1 i 0
    (while (<= i 10)
      (push! r (lambda () (+ i 1)))
      (inc! i)))
  (map (lambda (f) (f)) r)) ; => (12 12 12 12 12 12 12 12 12 12 12)

functools.partial

from functools import partial

def adder(x, y):
    return x + y

xs = [lambda y : adder(x, y) for x in xrange(10)]
print [fn(0) for fn in xs]

zs = [partial(adder, z) for z in xrange(10)]
print [fn(0) for fn in zs]

# [9, 9, 9, 9, 9, 9, 9, 9, 9, 9]
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

追記

これがうまくいくのは再帰呼び出しのスタックで参照先が異なるからということで理由は分かる。

def loop(n):
    r = []
    def rec(i):
        if i >= n:
            return
        r.append(lambda : i + 1)
        rec(i + 1)
    rec(0)
    return r

xs =  loop(10)
print [x() for x in xs]
# [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]