[racket] define-provide-syntax + contract-out

From: Matthias Felleisen (matthias at ccs.neu.edu)
Date: Thu Feb 27 13:48:01 EST 2014


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



Posted on the users mailing list.