#lang scheme/base (require scheme/contract (for-syntax scheme/base)) (provide memory/c apply/c poly/c) (with-contract poly-internals ([memory/c (->* [] [ #:name any/c #:to any/c #:from any/c #:weak boolean? #:equal (or/c 'eq 'eqv 'equal) #:table (-> (and/c hash? (not/c immutable?))) ] (values flat-contract? flat-contract?))] [apply/c (->* [any/c] [#:name any/c] contract?)]) (define (memory/c #:name [name "memory/c"] #:to [to (format "~a:to" name)] #:from [from (format "~a:from" name)] #:weak [weak? #t] #:equal [equal 'eq] #:table [make-table (case equal [(eq) (if weak? make-weak-hasheq make-hasheq)] [(eqv) (if weak? make-weak-hasheqv make-hasheqv)] [(equal) (if weak? make-weak-hash make-hash)])]) (let* ([table (make-table)]) (values (flat-named-contract from (lambda (v) (hash-set! table v #t) #t)) (flat-named-contract to (lambda (v) (hash-ref table v #f)))))) (define (apply/c c #:name [name (build-compound-type-name 'apply/c c)]) (make-proj-contract name (lambda (pos neg src name2 positive-position?) (lambda (p) (let* ([ctc (coerce-contract 'apply/c c)] [thunk (lambda () ((((proj-get ctc) ctc) pos neg src name2 positive-position?) p))]) (make-keyword-procedure (lambda (keys vals . args) (keyword-apply (thunk) keys vals args)) (case-lambda [() ((thunk))] [(a) ((thunk) a)] [(a b) ((thunk) a b)] [(a b c) ((thunk) a b c)] [(a b c d) ((thunk) a b c d)] [(a b c d e) ((thunk) a b c d e)] [(a b c d e f) ((thunk) a b c d e f)] [(a b c d e f g) ((thunk) a b c d e f g)] [(a b c d e f g h) ((thunk) a b c d e f g h)] [args (apply (thunk) args)]))))) procedure?))) (define-syntax (poly/c stx) (syntax-case stx () [(_ opts ... ([c- c+] ...) c) (quasisyntax/loc stx (apply/c #:name (quote #,stx) (recursive-contract (let-values ([(c- c+) (memory/c #:from 'c- #:to 'c+ opts ...)] ...) c))))]))