racket/collects/scribblings/guide/contracts-examples/3.ss
Robby Findler 765ec336e0 a little more progress
svn: r8205
2008-01-04 15:44:53 +00:00

108 lines
3.5 KiB
Scheme

;; chapter 3: A Dictionary
;; --- dictionary --------------------------------------------------------------
(module dictionary mzscheme
(require (lib "contract.ss") (lib "etc.ss"))
;; a contract utility
(define-syntax =>
(syntax-rules ()
[(=> antecedent consequent) (if antecedent consequent #t)]))
;; implementation
(define-struct dictionary (l value? eq?))
;; the keys should probably be another parameter (exercise)
(define (initialize p eq) (make-dictionary '() p eq))
(define (put d k v)
(make-dictionary (cons (cons k v) (dictionary-l d))
(dictionary-value? d)
(dictionary-eq? d)))
(define (remove d k)
(make-dictionary
(let loop ([l (dictionary-l d)])
(cond
[(null? l) l]
[(eq? (caar l) k) (loop (cdr l))]
[else (cons (car l) (loop (cdr l)))]))
(dictionary-value? d)
(dictionary-eq? d)))
(define (count d) (length (dictionary-l d)))
(define (value-for d k) (cdr (assq k (dictionary-l d))))
(define (has? d k) (pair? (assq k (dictionary-l d))))
(define (not-has? d) (lambda (k) (not (has? d k))))
;; end of implementation
;; interface
(provide/contract
;; predicates
[dictionary? (-> any/c boolean?)]
;; basic queries
;; how many items are in the dictionary?
[count (-> dictionary? natural-number/c)]
;; does the dictionary define key k?
[has? (->pp ([d dictionary?][k symbol?])
#t ;; pre
boolean?
result
((zero? (count d)) . => . (not result)))]
;; what is the value of key k in this dictionary?
[value-for (->r ([d dictionary?]
[k (and/c symbol? (lambda (k) (has? d k)))])
(dictionary-value? d))]
;; initialization
;; post condition: for all k in symbol, (has? d k) is false.
[initialize (->r ([p contract?][eq (p p . -> . boolean?)])
(and/c dictionary? (compose zero? count)))]
;; commands
;; Mitchell and McKim say that put shouldn't consume Void (null ptr) for v.
;; We allow the client to specify a contract for all values via initialize.
;; We could do the same via a key? parameter (exercise).
;; add key k with value v to this dictionary
[put (->pp ([d dictionary?]
[k (and symbol? (not-has? d))]
[v (dictionary-value? d)])
#t
dictionary?
result
(and (has? result k)
(= (count d) (- (count result) 1))
([dictionary-eq? d] (value-for result k) v)))]
;; remove key k from this dictionary
[remove (->pp ([d dictionary?]
[k (and/c symbol? (lambda (k) (has? d k)))])
#t
(and/c dictionary? not-has?)
result
(= (count d) (+ (count result) 1)))])
;; end of interface
)
;; --- tests -------------------------------------------------------------------
(module test mzscheme
(require (planet "test.ss" ("schematics" "schemeunit.plt" 1 2))
(planet "text-ui.ss" ("schematics" "schemeunit.plt" 1 2)))
(require (lib "contract.ss"))
(require dictionary)
(define d
(put (put (put (initialize (flat-contract integer?) =) 'a 2) 'b 2) 'c 1))
(test/text-ui
(make-test-suite
"dictionaries"
(make-test-case
"value for"
(assert = (value-for d 'b) 2))
(make-test-case
"has?"
(assert-false (has? (remove d 'b) 'b)))
(make-test-case
"count"
(assert = 3 (count d))))))
(require test)