53 lines
1.0 KiB
Racket
53 lines
1.0 KiB
Racket
#lang racket/base
|
|
;; Poor-man's memoization.
|
|
|
|
(provide memoize1)
|
|
|
|
(define sentinel (cons #f #f))
|
|
|
|
(define (memoize1 f)
|
|
(define results (make-weak-hash))
|
|
(lambda (arg)
|
|
(hash-ref results arg (lambda ()
|
|
(define val (f arg))
|
|
(hash-set! results arg val)
|
|
val))))
|
|
|
|
(module+ test
|
|
(require rackunit)
|
|
|
|
(define call-counter 0)
|
|
|
|
(define (raw x)
|
|
(set! call-counter (+ call-counter 1))
|
|
(gensym 'raw-result))
|
|
|
|
(define cooked (memoize1 raw))
|
|
|
|
;; These tests will *likely* pass, but if garbage collection strikes
|
|
;; at an inopportune moment, they may fail.
|
|
|
|
(collect-garbage)
|
|
|
|
(define v (cons 1 2))
|
|
|
|
(check-equal? call-counter 0)
|
|
(check-eq? (cooked v) (cooked v))
|
|
(check-equal? call-counter 1)
|
|
|
|
(set! v (cons 1 2))
|
|
|
|
(check-equal? call-counter 1)
|
|
(check-equal? (cooked v) (cooked v))
|
|
(check-equal? call-counter 1)
|
|
|
|
(set! v (cons 1 2))
|
|
|
|
(collect-garbage)
|
|
(collect-garbage)
|
|
(collect-garbage)
|
|
|
|
(check-equal? call-counter 1)
|
|
(check-equal? (cooked v) (cooked v))
|
|
(check-equal? call-counter 2))
|