Curiously, the contract for `response` also requires an (-> output-port? void?) procedure [1]. The source code agrees. But the examples given in the docs don't include a (void) return value. Yet they do work. So perhaps there's a tiny bug where `response` is being more lenient than it's supposed to be.
[1] http://docs.racket-lang.org/web-server/http.html?q=response#%28def._%28%28lib._web-server%2Fhttp%2Fresponse-structs..rkt%29._response%29%29 On Fri, Mar 6, 2015 at 4:40 PM, Alexis King <lexi.lam...@gmail.com> wrote: > I do sort of agree that the void? requirement is strange and unneeded. > It’s usually only used to indicate that a function provided by some module > returns #<void>, but callback functions are usually specified with any as > the return value to allow precisely this sort of thing. > > On Mar 6, 2015, at 16:26, Matthew Butterick <m...@mbtype.com> wrote: > > From the error message, I changed the lambda to return (void) and then it >> worked. >> I think maybe the contract is wrong but frankly I don't understand much >> about contracts. > > > The contract, by definition, is always right ;) > > In this case, `response/output` takes as its first argument a procedure > that accepts an output-port and returns void. [1] In contract-speak this is > commonly written with dot notation as: > > (output-port? . -> . void?) > > but it appears in error messages, like the one above, with the equivalent > notation: > > (-> output-port? void?) > > Note also that the error says the contract violation was "in the range of > the 1st argument of" ... [giant contract follows]. That helps track down > the error. The contract for the first argument is '(-> output-port? > void?)'. This is a procedure contract. And "the range of" a procedure > contract means the contract on the return value. Which in this case is > `void?`. So the complaint is that the procedure given in the first argument > is returning '11' when it should be returning void. > > Why is (-> output-port? void?) the contract for the first arg of > `response/output`? The idea is that you write to the output-port directly > rather than returning a value to the caller. Insisting on void as a return > value imposes an extra measure of discipline, and sets an expectation. > > The reason your 'not-working' dispatcher is not working is that > `write-bytes` does two things: it sends bytes to the output port, but then > also returns the number of bytes written. [2] So this procedure: > > (λ (op) (write-bytes #"Hello world" op)) > > is defective because it returns the number of bytes. Meaning, it breaks > the contract, which demands void. (That's also why your error is '11': > that's the number of bytes in "Hello world"). > > But your revised procedure: > > (λ (op) (write-bytes #"Hello world" op) (void)) > > Meets the contract because it ignores the return value from `write-bytes` > and returns (void) instead. > > You should repeat this technique whenever you use `response/output`. > > You can also look into `response/full` and `response/xexpr`, which can be > a more convenient way of making simple HTML or text responses. > > > > [1] > http://docs.racket-lang.org/web-server/http.html?q=response%2Foutput#%28def._%28%28lib._web-server%2Fhttp%2Fresponse-structs..rkt%29._response%2Foutput%29%29 > > which cross-references > > > http://docs.racket-lang.org/web-server/http.html?q=response%2Foutput#%28def._%28%28lib._web-server%2Fhttp%2Fresponse-structs..rkt%29._response%29%29 > > [2] > http://docs.racket-lang.org/reference/Byte_and_String_Output.html?q=write-bytes#%28def._%28%28quote._~23~25kernel%29._write-bytes%29%29 > > which cross-references > > > http://docs.racket-lang.org/reference/Byte_and_String_Output.html?q=write-bytes#%28def._%28%28quote._~23~25kernel%29._write-string%29%29 > > > > On Fri, Mar 6, 2015 at 3:48 PM, André Matheus <amath...@mac.com> wrote: > >> Hi, starting a project of mine, I've setup a dispatch rule and a function >> to return the response. >> To make things simple, I've used response/output, with a lambda writing >> to the output-port. >> However, I've got the error: >> >> response/output: contract violation >> expected: void? >> given: 11 >> in: the range of >> the 1st argument of >> (->* >> ((-> output-port? void?)) >> (#:code >> number? >> #:headers >> (listof header?) >> #:message >> bytes? >> #:mime-type >> (or/c bytes? #f) >> #:seconds >> number?) >> response?) >> contract from: >> <pkgs>/web-server-lib/web-server/http/response-structs.rkt >> blaming: /home/amatheus/Dropbox/focus/todagendas/teste.rkt >> (assuming the contract is correct) >> at: <pkgs>/web-server-lib/web-server/http/response-structs.rkt:41.2 >> context...: >> /usr/share/racket/collects/racket/contract/private/blame.rkt:143:0: >> raise-blame-error16 >> >> /usr/share/racket/pkgs/web-server-lib/web-server/http/response.rkt:115:12 >> >> So I've tried to use a response, with the same lambda, and it worked. >> From the error message, I changed the lambda to return (void) and then it >> worked. >> >> I think maybe the contract is wrong but frankly I don't understand much >> about contracts. >> >> I've setup some code that exposes the problem. Navigating to "/working" >> and "/fixed" works >> fine; navigating to "/not-working" exposes the problem. >> >> #lang racket >> (require web-server/dispatch >> web-server/servlet-env >> net/url >> web-server/http/request-structs >> web-server/http/response-structs) >> >> (define (not-working req) >> (response/output (λ (op) (write-bytes #"Hello world" op)))) >> >> (define (working req) >> (response >> 301 #"OK" >> (current-seconds) TEXT/HTML-MIME-TYPE >> empty >> (λ (op) (write-bytes #"Hello world" op)))) >> >> (define (fixed req) >> (response/output (λ (op) (write-bytes #"Hello world" op) (void)))) >> >> (define (url->request u) >> (make-request #"GET" (string->url u) empty >> (delay empty) #f "1.2.3.4" 80 "4.3.2.1")) >> >> (define-values (agenda-dispatch agenda-url) >> (dispatch-rules >> [("working") working] >> [("not-working") not-working] >> [("fixed") fixed])) >> >> (define (main) >> (serve/servlet agenda-dispatch >> #:servlet-regexp #rx"" >> #:servlet-path "")) >> >> (module+ main >> (main)) >> >> The contracts in response-structs.rkt: >> >> (provide/contract >> [struct response >> ([code number?] >> [message bytes?] >> [seconds number?] >> [mime (or/c false/c bytes?)] >> [headers (listof header?)] >> [output (output-port? . -> . void)])] >> [response/full (-> number? bytes? number? (or/c false/c bytes?) (listof >> header?) (listof bytes?) response?)] >> [response/output (->* ((-> output-port? void?)) >> (#:code number? >> #:message bytes? >> #:seconds number? >> #:mime-type (or/c bytes? #f) >> #:headers (listof header?)) >> response?)] >> [TEXT/HTML-MIME-TYPE bytes?]) >> >> Is the contract wrong or am I doing something weird? >> >> Thanks, >> >> André >> >> ____________________ >> Racket Users list: >> http://lists.racket-lang.org/users >> >> > ____________________ > Racket Users list: > http://lists.racket-lang.org/users > > >
____________________ Racket Users list: http://lists.racket-lang.org/users