#lang racket/base (require racket/dict racket/match racket/function (for-syntax racket/base racket/list)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; HIGHER ORDER TOOLS ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; Automatic case-lambda repetition ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define-for-syntax (split-syntax-at orig stx id) (let loop ([found #f] [seen null] [stx stx]) (syntax-case stx [] [(head . tail) (and (identifier? #'head) (free-identifier=? #'head id)) (if found (raise-syntax-error #f (format "duplicate occurrence of ~a" (syntax-e id)) orig #'head) (loop (list (reverse seen) #'head #'tail) (cons #'head seen) #'tail))] [(head . tail) (loop found (cons #'head seen) #'tail)] [_ found]))) (define-for-syntax (expand-ellipsis-clause stx pattern expr) (cond [(split-syntax-at stx pattern #'(... ...)) => (lambda (found) (syntax-case found [...] [([pre ... repeat] (... ...) [count post ... . tail]) (and (identifier? #'repeat) (exact-nonnegative-integer? (syntax-e #'count))) (build-list (add1 (syntax-e #'count)) (lambda (i) (with-syntax ([(var ...) (generate-temporaries (build-list i (lambda (j) #'repeat)))] [body expr]) (list (syntax/loc pattern (pre ... var ... post ... . tail)) (syntax/loc expr (let-syntax ([the-body (lambda _ (with-syntax ([(repeat (... ...)) #'(var ...)]) #'body))]) the-body))))))] [(pre mid post) (raise-syntax-error #f "expected ellipsis between identifier and natural number literal" stx #'mid)]))] [else (list (list pattern expr))])) (define-syntax (case-lambda* stx) (syntax-case stx [] [(_ [pattern body] ...) (with-syntax ([([pattern body] ...) (append-map (lambda (p e) (expand-ellipsis-clause stx p e)) (syntax->list #'(pattern ...)) (syntax->list #'(body ...)))]) (syntax/loc stx (case-lambda [pattern body] ...)))])) (define-syntax (make-intermediate-procedure stx) (syntax-case stx [quote] [(_ (quote name) positional-clause ... #:keyword keyword-clause) (syntax/loc stx (make-keyword-procedure (let* ([name (case-lambda keyword-clause)]) name) (let* ([name (case-lambda* positional-clause ...)]) name)))])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; Degenerate Functions ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define (identity x) x) (define-syntax (thunk stx) (syntax-case stx () [(thunk body ...) (syntax/loc stx (make-keyword-thunk (lambda () body ...)))])) (define (make-keyword-thunk f) (make-intermediate-procedure 'thunk-function [(x ... 8) (f)] [xs (f)] #:keyword [(ks vs . xs) (f)])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; Higher-Order Boolean Operations ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define conjoin (case-lambda* [(f ... 8) (make-intermediate-procedure 'conjoined [(x (... ...) 8) (and (f x (... ...)) ...)] [xs (and (apply f xs) ...)] #:keyword [(keys vals . args) (and (keyword-apply f keys vals args) ...)])] [fs (make-intermediate-procedure 'conjoined [(x ... 8) (andmap (lambda (f) (f x ...)) fs)] [xs (andmap (lambda (f) (apply f xs)) fs)] #:keyword [(keys vals . args) (andmap (lambda (f) (keyword-apply f keys vals args)) fs)])])) (define disjoin (case-lambda* [(f ... 8) (make-intermediate-procedure 'disjoined [(x (... ...) 8) (or (f x (... ...)) ...)] [xs (or (apply f xs) ...)] #:keyword [(keys vals . args) (or (keyword-apply f keys vals args) ...)])] [fs (make-intermediate-procedure 'disjoined [(x ... 8) (ormap (lambda (f) (f x ...)) fs)] [xs (ormap (lambda (f) (apply f xs)) fs)] #:keyword [(keys vals . args) (ormap (lambda (f) (keyword-apply f keys vals args)) fs)])])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; Function Invocation (partial or indirect) ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define-syntax-rule (cons2 one two rest) (let*-values ([(ones twos) rest]) (values (cons one ones) (cons two twos)))) (define merge-keywords (match-lambda* [(or (list _ '() '() keys vals) (list _ keys vals '() '())) (values keys vals)] [(list name (and keys1* (cons key1 keys1)) (and vals1* (cons val1 vals1)) (and keys2* (cons key2 keys2)) (and vals2* (cons val2 vals2))) (cond [(keyword