あああ、僕もうっかりしてました。
On Lispの
memoize
なんですけど。久々にGauche起動してValvallowさんに従って試してみたら、次のような結果になりました。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
gosh> (define (memoize fn) | |
(let ((cache (make-hash-table 'equal?))) | |
(lambda args | |
(let ((val (hash-table-get cache args #f))) | |
(if val val | |
(hash-table-put! cache args (apply fn args))))))) | |
memoize | |
gosh> (define (fib n) | |
(if (< n 2) | |
1 | |
(+ (fib (- n 1))(fib (- n 2))))) | |
fib | |
gosh> (time (fib 35)) | |
;(time (fib 35)) | |
; real 2.451 | |
; user 2.450 | |
; sys 0.000 | |
14930352 | |
gosh> (time ((memoize fib) 35)) | |
;(time ((memoize fib) 35)) | |
; real 2.580 | |
; user 2.570 | |
; sys 0.000 | |
#<undef> | |
gosh> (time ((memoize fib) 35)) | |
;(time ((memoize fib) 35)) | |
; real 2.438 | |
; user 2.430 | |
; sys 0.000 | |
#<undef> | |
gosh> |
あれ、全然速くなっていない……。
考えてみれば当然で、手続き
memoize
は呼び出す度に新しくレキシカル環境を作ります。と言う事は。
cache
に保存される筈のハッシュテーブルは、手続きmemoize
が呼び出される度に新しくクロージャの中で作られて、そしてmemoize
の起動が終了する度にその寿命を全うするわけです。従って、
hash-table-get
の返り値は毎度必ず#f
になる、って事です。これじゃあ意味無い。
んで、On Lispを良く見てみると、実は「敢えて」
memoize
とそれが受け取る関数引数を合わせて大域環境に束縛しているんです。これが手続き
memoize
の正しい使い方です。本に依ると、大域変数slowid
に束縛されている以上、クロージャ、翻って使用されたハッシュテーブルが廃棄されません。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
gosh> (define slowid (memoize fib)) | |
slowid | |
gosh> (time (slowid 35)) | |
;(time (slowid 35)) | |
; real 2.549 | |
; user 2.510 | |
; sys 0.000 | |
#<undef> | |
gosh> (time (slowid 35)) | |
;(time (slowid 35)) | |
; real 0.000 | |
; user 0.000 | |
; sys 0.000 | |
14930352 | |
gosh> |
ご覧になれば分かるでしょうが、一回目の大域変数
slowid
に35を付けた時の呼び出しは遅いです。反面、クロージャ/ハッシュテーブルは依然と大域変数slowid
に束縛されたまま、なんで、二回目の呼び出し時は高速なハッシュ検索により、時間が殆どかからず値を見つけ出している事が分かると思います。これが
memoize
の使い方です。
0 件のコメント:
コメントを投稿