[racket] Contract for function with vararg

From: Roman Klochkov (kalimehtar at mail.ru)
Date: Sun Jun 29 20:44:36 EDT 2014

 2Robby:

> (define/contract (test f) (-> (->* (input-port? any/c) #:rest list? any) any)
    1)
> (test (λ (x y) 2))
. . test: contract violation
  expected: a procedure that accepts 2 non-keyword arguments and arbitrarily many more
  given: #<procedure>
  accepts: 2 arguments
  in: the 1st argument of
      (->
       (->* (input-port? any/c) #:rest list? any)
       any)
  contract from: (function test)
  blaming: anonymous-module
  at: unsaved-editor322:14.20

So doesn't work.

2Alexander:

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



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.


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/20140630/1539e798/attachment-0001.html>

Posted on the users mailing list.