minimart-2014/minimart/memoize.rkt

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))