contract for an "overloaded function"

22 views
Skip to first unread message

Ryan Kramer

unread,
Nov 29, 2019, 2:28:39 PM11/29/19
to Racket Users
I'm not exactly sure what I mean by "overloaded function", but I think you will understand. I'm looking for something that would allow me to write a function contract like

(magic-> [integer? integer? -> integer?]
         
[string? symbol? -> string?]
         
[string? ...+ -> string?])

The above contract would mean:
  * If the function is given an argument list that satisfies (cons/c integer? (cons/c integer? null?)), then the return value must be an integer?
  * Else if the function is given an argument list that satisfies (cons/c string? (cons/c symbol? null?)), then the return value must be a string?
  * Else if the function is given an argument list that satisfies (cons/c string? (list/c string?)), then the return value must be a string?
  * Else the caller is blamed for not providing correct arguments.

(I don't think I need support for keyword arguments)

Does this already exist in a library somewhere? If not, it doesn't look too hard for me to roll my own but I am (perhaps prematurely) concerned about the performance. Would the following approach be reasonable?

(define-syntax-rule (magic-> [dom ... range-expr] ...)
  ; We should make sure that every dom and range is a flat-contract?
  (make-contract
   #:name '(magic-> [dom ... range-expr] ...)
   #:first-order procedure?
   #:projection
   (λ (blame)
     (λ (proc)
       (λ args
         (cond
           [((list/c dom ...) args)
            (let ([range ((contract-projection range-expr) blame)])
              (range (apply proc args)))]
           ...
           [else
            (raise-blame-error
             (blame-swap blame) args
             '(expected "a conforming argument list" given: "~e")
             args)]))))))

(define/contract (blah a b)
  (magic-> [integer? string? list?]
           [string? integer? (list/c string? integer?)]
           ; This one will throw a contract violation
           [integer? integer? integer?])
  (list a b))

David Storrs

unread,
Nov 29, 2019, 2:51:52 PM11/29/19
to Ryan Kramer, Racket Users

--
You received this message because you are subscribed to the Google Groups "Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to racket-users...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/racket-users/b21a5512-521f-4c6e-8e4e-ca6d3528df8c%40googlegroups.com.

Ryan Kramer

unread,
Nov 29, 2019, 3:15:01 PM11/29/19
to Racket Users
Thanks, but I don't think `case->` works for me. It looks like it chooses a case purely based on the number of arguments. The following example, when given two arguments, will always choose the integer? case even if both arguments are strings.

(case-> [-> integer? integer? list?]
       
[-> string? string? list?])

Ben Greenman

unread,
Nov 29, 2019, 4:42:51 PM11/29/19
to Ryan Kramer, Racket Users
Try ->i. I wouldn't worry about performance until makes itself a problem.
> --
> You received this message because you are subscribed to the Google Groups
> "Racket Users" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to racket-users...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/racket-users/73132ad9-7722-432a-8328-0d4c38bbb5a1%40googlegroups.com.
>
Reply all
Reply to author
Forward
0 new messages