diff --git a/define-curry/define-curry-test.rkt b/define-curry/define-curry-test.rkt new file mode 100644 index 0000000..e16f318 --- /dev/null +++ b/define-curry/define-curry-test.rkt @@ -0,0 +1,20 @@ +#lang racket/base +(module+ test + (require rackunit racket/string syntax-parse-example/define-curry/define-curry) + + (test-case "insert-between" + (define/curry (insert-between mid left right) + (string-join (list left mid right) "")) + + (define dash-between (insert-between "-")) + + (check-equal? (dash-between "left" "right") "left-right") + (check-equal? (((insert-between "-") "left") "right") "left-right") + + (check-true + (string-suffix? (symbol->string (object-name insert-between)) + "6:4")) + + (check-exn #rx"arity mismatch" ;; object name + (lambda () (insert-between 2 3 3 4 4 44)))) +) diff --git a/define-curry/define-curry.rkt b/define-curry/define-curry.rkt new file mode 100644 index 0000000..a006ec4 --- /dev/null +++ b/define-curry/define-curry.rkt @@ -0,0 +1,20 @@ +#lang racket +(provide define/curry) +(require (for-syntax syntax/parse)) + +(begin-for-syntax + (define-syntax-class name-params + #:description "name and parameters clause" + (pattern (name:id params:id ...+) + #:fail-when (check-duplicate-identifier + (syntax->list #'(params ...))) + "duplicate parameter name"))) + +(define-syntax (define/curry stx) + (syntax-parse stx + [(_ np:name-params body ...+) + #`(define np.name + (curry + #,(syntax/loc stx + (λ (np.params ...) body ...))))])) + diff --git a/define-curry/define-curry.scrbl b/define-curry/define-curry.scrbl new file mode 100644 index 0000000..05d5776 --- /dev/null +++ b/define-curry/define-curry.scrbl @@ -0,0 +1,30 @@ +#lang syntax-parse-example +@require[ + (for-label racket/base syntax/parse syntax-parse-example/define-curry/define-curry)] + +@(define define-curry-eval + (make-base-eval '(require racket/string syntax-parse-example/define-curry/define-curry))) + +@title{@tt{define/curry}} +@stxbee2021["agj" 5] + +@; ============================================================================= + +@defmodule[syntax-parse-example/define-curry/define-curry]{} + +@defform[(define/curry (fn-id arg-id ...+) body ...+)]{ + Defines an automatically currying procedure. + + @examples[#:eval define-curry-eval + (define/curry (insert-between mid left right) + (string-join (list left mid right) "")) + (define dash-between (insert-between "-")) + (dash-between "left" "right") + ] + + The macro uses @racket[syntax/loc] to give newly-defined functions + names that point to their definition rather than to the macro body. + + @racketfile{define-curry.rkt} + +} diff --git a/index.scrbl b/index.scrbl index 43120d9..6c3a6bd 100644 --- a/index.scrbl +++ b/index.scrbl @@ -19,6 +19,7 @@ @include-example{first-class-or} @include-example{optional-assert} @include-example{make-variable} +@include-example{define-curry} @include-example{cross-macro-communication} @include-example{let-star} @include-example{while-break}