[racket] define-provide-syntax + contract-out
The c-out indirection does it:
#lang racket
(provide
(contract-out
[sin (-> number? number?)]))
(module macro1 racket
(require racket/provide-syntax)
(provide define-special)
(define-provide-syntax (r-out stx)
(syntax-case stx ()
[(_ name)
#'(rename-out [name foobar])]))
(define-syntax (define-special stx)
(syntax-case stx ()
[(_ (name arg) body ...)
#'(begin
(module+ inner
(define (name arg) body ...)
(provide (r-out name))))])))
(module macro2 racket
(require racket/provide-syntax)
(require racket/contract) ; nope
(require (for-template racket/contract)) ; nope
(provide define-special2)
(define-syntax (define-special2 stx)
(syntax-case stx ()
[(_ (name arg) contract body ...)
#'(begin
(define (name arg) body ...)
(module+ safe
(require racket/contract) ; nope
(provide (contract-out [name contract]))))])))
(require 'macro1 'macro2)
(define-special (func x) x)
;> [works fine]
(define-special2 (func2 x) (string? . -> . string?) x)
;> contract-out: not a provide sub-form in: (contract-out (func2 (-> string? string?)))
TEST MODULE:
#lang racket
(require (submod "junk.rkt" safe) rackunit)
(check-equal? (func2 "hello") "hello")
(check-exn exn:fail:contract? (λ () (func2 42)))
-- Matthias
On Feb 27, 2014, at 11:26 AM, Matthew Butterick <mb at mbtype.com> wrote:
> I've learned about 'define-provide-syntax', and it works as expected in macro1 below with rename-out.
>
> Macro2, which uses contract-out, doesn't work, reporting the error "contract-out: not a provide sub-form." I gather this is the result of the macro not seeing a binding for contract-out.
>
> But where is it supposed to get the binding? I've moved (require racket/contract) around the macro to no avail.
>
> PS. What is the point of this macro? To define a function with a contract in the usual way in the module source, but then move the contract inside a submodule, so it is only invoked on request.
>
> ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
> #lang racket/base
>
> (module macro1 racket
> (require racket/provide-syntax)
>
> (provide define-special)
>
> (define-provide-syntax (r-out stx)
> (syntax-case stx ()
> [(_ name)
> #'(rename-out [name foobar])]))
>
> (define-syntax (define-special stx)
> (syntax-case stx ()
> [(_ (name arg) body ...)
> #'(begin
> (module+ inner
> (define (name arg) body ...)
> (provide (r-out name))))])))
>
>
> (module macro2 racket
> (require racket/provide-syntax)
> (require racket/contract) ; nope
> (require (for-syntax racket/contract)) ; nope
>
> (provide define-special2)
>
> (define-provide-syntax (c-out stx)
> (syntax-case stx ()
> [(_ name contract)
> #'(contract-out [name contract])]))
>
> (define-syntax (define-special2 stx)
> (syntax-case stx ()
> [(_ (name arg) contract body ...)
> #'(begin
> (define (name arg) body ...)
> (module+ safe
> (require racket/contract) ; nope
> (provide (c-out name contract))))])))
>
> (require 'macro1 'macro2)
>
> (define-special (func x) x)
> ;> [works fine]
> (define-special2 (func2 x) (string? . -> . string?) x)
> ;> contract-out: not a provide sub-form in: (contract-out (func2 (-> string? string?)))
> ____________________
> Racket Users list:
> http://lists.racket-lang.org/users