[racket] Contract for function with vararg

From: Alexander D. Knauth (alexander at knauth.org)
Date: Sun Jun 29 21:33:08 EDT 2014

On Jun 29, 2014, at 8:44 PM, Roman Klochkov <kalimehtar at mail.ru> wrote:

> 
> procedure-has-arity is not needed. I can write:
> > (define/contract (test f) (-> (or/c 
>                                  (-> input-port? any/c any)
>                                  (-> input-port? any/c any/c any)
>                                  (-> input-port? any/c any/c any/c any)
>                                  (->* (input-port? any/c) #:rest list? any)) any)
>     1)
> > (test (λ (x y) 2))
> 1
> 

procedure-has-arity is needed if f is something like (λ (x y . rst) x).  

In this case or/c would report an error because f would match more than one of the contracts in the or/c.  
That’s also why it needs to be procedure-has-arity, and not procedure-arity-includes.  

> But I need any number of args, more than two. I can, of course write something like
> (define-syntax (make-contract stx)
>     (syntax-case stx ()
>       [_ (with-syntax ([(CLAUSES ...) (for/list ([i 100]) ;;; hope 100 enough many
>                                         #`(-> input-port? any/c 
>                                               #,@(for/list ([j i]) #'any/c)))])
>            #'(or/c CLAUSES ... (->* (input-port? any/c) #:rest list? any)))]))
> 
> But it is very slow and clumsy.
> 

In that case, you could use this:
http://docs.racket-lang.org/reference/Building_New_Contract_Combinators.html

> 
> Sun, 29 Jun 2014 18:43:15 -0500 от Robby Findler <robby at eecs.northwestern.edu>:
> Why isn't:
> 
>   (->* (input-port? any/c) #:rest list? any)
> 
> by itself the contract that you want?
> 
> Robby
> 
> 
> On Sun, Jun 29, 2014 at 12:08 PM, Alexander D. Knauth
> <alexander at knauth.org> wrote:
> > You can use or/c to do this, as long as you guard them like this so that no
> > more than one contract matches at a time:
> > (or/c
> > (and/c (procedure-has-arity/c 2) (-> input-port? any/c any))
> > (and/c (procedure-has-arity/c 3) (-> input-port? any/c any/c any))
> > (and/c (procedure-has-arity/c 4) (-> input-port? any/c any/c any/c any))
> > (->* (input-port? any/c) #:rest list? any)
> > )
> >
> > Or, you could use if/c from unstable/contract, or define a cond/c macro like
> > this:
> > (require unstable/contract)
> > (define-syntax cond/c
> > (syntax-rules (else)
> > [(cond/c) none/c]
> > [(cond/c [else else-c])
> > else-c]
> > [(cond/c [pred then-c] clause ...)
> > (if/c pred
> > then-c
> > (cond/c clause ...))]))
> >
> > (cond/c [(procedure-has-arity/c 2) (-> input-port? any/c any)]
> > [(procedure-has-arity/c 3) (-> input-port? any/c any/c any)]
> > [(procedure-has-arity/c 4) (-> input-port? any/c any/c any/c any)]
> > [else (->* (input-port? any/c) #:rest list? any)])
> >
> > By the way it has to be procedure-has-arity/c, not
> > procedure-includes-arity/c:
> > (define (procedure-has-arity/c arity)
> > (define normalized-arity (normalize-arity arity))
> > (flat-named-contract
> > `(procedure-has-arity/c ,normalized-arity)
> > (λ (f)
> > (and (procedure? f)
> > (arity=? (procedure-arity f) normalized-arity)))))
> >
> > On Jun 29, 2014, at 8:00 AM, Roman Klochkov <kalimehtar at mail.ru> wrote:
> >
> > How to make a contract, that accepts
> > (-> input-port? any/c any)
> > (-> input-port? any/c any/c any)
> > (-> input-port? any/c any/c any/c any)
> > ...
> > and
> > (->* (input-port? any/c) #:rest list? any)
> >
> >
> > So theare should be at least two args and first arg should be input-port.
> >
> > --
> > Roman Klochkov
> >
> > ____________________
> > Racket Users list:
> > http://lists.racket-lang.org/users
> >
> >
> >
> > ____________________
> > Racket Users list:
> > http://lists.racket-lang.org/users
> >
> 
> 
> -- 
> Roman Klochkov

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/users/archive/attachments/20140629/30918fd3/attachment.html>

Posted on the users mailing list.