#lang racket/base ;; Poor-man's hash consing. (provide canonicalize) (define canonical-values (make-weak-hash)) (define sentinel (cons #f #f)) (define (canonicalize val) (cond [(or (struct-type? val) (symbol? val) (fixnum? val)) ;; These values already have unique representations. val] [else (define b (hash-ref canonical-values val (lambda () (define new-b (make-weak-box val)) (hash-set! canonical-values val new-b) #f))) (if (not b) (canonicalize val) (let ((v (weak-box-value b sentinel))) (if (eq? v sentinel) (canonicalize val) v)))])) (module+ test (require rackunit) (define v1 (canonicalize (cons 1 2))) (let ((v2 (canonicalize (cons 1 2)))) (check-eq? v1 v2)) (collect-garbage) (check-equal? (hash-count canonical-values) 1) (let ((v2 (canonicalize (cons 1 2)))) (check-eq? v1 v2)) (set! v1 (canonicalize (cons 1 2))) (collect-garbage) (check-equal? (hash-count canonical-values) 1) (let ((v2 (canonicalize (cons 1 2)))) (check-eq? v1 v2)) (set! v1 #f) (collect-garbage) (check-equal? (hash-count canonical-values) 0))