Re: [racket-users] Advantage of ->d over ->i
On Fri, Dec 1, 2017 at 10:08 PM, Ben Greenmanwrote: > Let me make sure I understand: > > 1. A converter is like a two-way function, lets say (A . <-> . B) > 2. If someone composes two incompatible converters, like (integer? . > <-> . symbol?) and (string? . <-> . boolean?) then they should get an > error that points to the place where they tried to do the composing. > > It looks like the code above is using the contract on > `compose-converters` to meet goal #2. > Is that all right? > Yes, all of this is correct. I will have to think about/play with your suggestion some more because I haven't used parametric->/c before (beyond playing with it when I've thought it might be what I was looking for and decided it wasn't). However, I do know that at least one of the "too many things at once" that the contract on compose-converters is doing is because of a simplification I made for this example. In the actual code where I encountered this, I provide only a protected interface for constructing values, so the equivalent of: (define/contract make-converter (->i ([encoded/c contract?] [encoded->native (encoded/c native/c) (-> encoded/c native/c)] [native/c contract?] [native->encoded (encoded/c native/c) (-> native/c encoded/c)]) [_ converter?]) converter) So I definitely agree that it shouldn't be up to the contract on compose-converters to ensure that its arguments are valid converters; its job should just be to ensure that they are compatible. -Philip -- 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+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [racket-users] Advantage of ->d over ->i
Let me make sure I understand: 1. A converter is like a two-way function, lets say (A . <-> . B) 2. If someone composes two incompatible converters, like (integer? . <-> . symbol?) and (string? . <-> . boolean?) then they should get an error that points to the place where they tried to do the composing. It looks like the code above is using the contract on `compose-converters` to meet goal #2. Is that all right? Anyway, I think the contract for `compose-converters` should ONLY try to make sure `compose-converters` is doing the right thing. Something like: ``` (define/contract (compose-converters g f) (parametric->/c [A B C] (-> (B . <-> . C) (A . <-> . B) (A . <-> . C))) ) ``` Then the `...` should try to meet goal #2 by putting a stronger contract on one of the converters (using something like `define/contract`). I don't think ->d is a good answer because I don't think a dependent contract on "compose" is a good answer -- it's doing too many things at once. [[ Now I'm thinking the docs should make ->d even harder to find ... every time I ever thought that I wanted ->d, I was better off making a new contract combinator and using it with -> or something. ]] -- 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+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
[racket-users] Advantage of ->d over ->i
I recently encountered a case where a contract that (as far as I can tell) cannot be written using ->i can be easily expressed using ->d. This surprised me, since I thought that ->i was strictly better than ->d (given that the docs for ->d say, "This contract is here for backwards compatibility; any new code should use ->i instead."). Specifically, using ->d I can express a mutual dependency between the arguments of a function (an extended example follows), whereas ->i raises an error if "generation of 's contract depends on 's value", even if depends on and depends on . I wonder if the docs should reflect that there are situations when ->d has advantages over ->i. (Or maybe there already is a way to do this with ->i, but the limitations seem to be inherent to its guarantees.) For a motivating example, consider an abstraction for pairs of functions that convert values between an "encoded" representation and a "native" representation: > #lang racket > (struct converter (encoded/c encoded->native native/c native->encoded) > #:transparent) > (define (converter/c #:extra-encoded/c [extra-encoded/c any/c] > #:extra-native/c [extra-native/c any/c]) > (rename-contract >(struct/dc converter > [encoded/c contract?] > [encoded->native >(encoded/c native/c) >(-> (and/c encoded/c extra-encoded/c) >(and/c native/c extra-native/c))] > [native/c contract?] > [native->encoded >(encoded/c native/c) >(-> (and/c native/c extra-native/c) >(and/c encoded/c extra-encoded/c))]) >`(converter/c #:extra-encoded/c ,(contract-name extra-encoded/c) > #:extra-native/c ,(contract-name extra-native/c > (define/contract (converter-decode c encoded) > (->i ([c (converter/c)] > [encoded (c) (converter-encoded/c c)]) >[_ (c) (converter-native/c c)]) > ((converter-encoded->native c) encoded)) > (define/contract (converter-encode c native) > (->i ([c (converter/c)] > [native (c) (converter-native/c c)]) >[_ (c) (converter-encoded/c c)]) > ((converter-native->encoded c) native)) A nice addition would be an operation to compose converters, constructing a converter from the encoded representation of converter A to the native representation of converter B: > (define unsafe-compose-converters > (match-lambda** > [{(converter a:encoded/c a:encoded->native a:native/c > a:native->encoded) > (converter b:encoded/c b:encoded->native b:native/c > b:native->encoded)} >(converter a:encoded/c > (compose1 b:encoded->native a:encoded->native) > b:native/c > (compose1 a:native->encoded b:native->encoded))])) The next step is to protect this operation with a contract requiring that the two converters use a compatible intermediate representation. Specifically, we want to insist that the encoded->native function of converter A must always produce values satisfying the encoded/c contract of converter B and that the native->encoded function of converter B must always produce values satisfying the native/c contract of converter A. This is easily done using ->d (though note that we must explicitly test that both arguments are converters before using them in the contract, as ->d, unlike ->i, does not guarantee this): > (define/contract compose-converters > (->d ([encoded-to-intermediate (converter/c #:extra-native/c > (if (converter? > intermediate-to-native) > (converter-encoded/c > intermediate-to-native) > any/c))] > [intermediate-to-native (converter/c #:extra-encoded/c > (if (converter? > encoded-to-intermediate) > (converter-native/c > encoded-to-intermediate) > any/c))]) >[_ (if (and (converter? encoded-to-intermediate) >(converter? intermediate-to-native)) > (converter/c #:extra-encoded/c (converter-encoded/c > encoded-to-intermediate) >#:extra-native/c (converter-native/c > intermediate-to-native)) > none/c)]) > unsafe-compose-converters) Now, if we compose two incompatible converters and try to use the result: > (define converter:string->number/false > (converter string? > string->number > (or/c number? #f) > (λ (native) >(if native >(number->string native) >"" > (define converter:number->number > (converter number? add1 number? sub1)) > (converter-decode (compose-converters converter:string->number/false >
Re: [racket-users] Raising arbitrary errors in Typed Racket
Why not use any-wrap/c? Robby On Fri, Dec 1, 2017 at 8:39 PM Sam Tobin-Hochstadtwrote: > Two notes: > > 1. It is unsafe to expose mutable data to untyped code via exceptions > without wrapping them. If you `(raise f)`, then untyped code could > catch the exception and call `f`. > > 2. You should inherit from `exn:fail` -- other `exn` types are for > non-standard exceptions such as `exn:break`. > > Sam > > On Fri, Dec 1, 2017 at 2:24 PM, Ben Greenman > wrote: > > That name sounds good to me. > > > > -- > > 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+unsubscr...@googlegroups.com. > > For more options, visit https://groups.google.com/d/optout. > > -- > 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+unsubscr...@googlegroups.com. > For more options, visit https://groups.google.com/d/optout. > -- 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+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [racket-users] Raising arbitrary errors in Typed Racket
Two notes: 1. It is unsafe to expose mutable data to untyped code via exceptions without wrapping them. If you `(raise f)`, then untyped code could catch the exception and call `f`. 2. You should inherit from `exn:fail` -- other `exn` types are for non-standard exceptions such as `exn:break`. Sam On Fri, Dec 1, 2017 at 2:24 PM, Ben Greenmanwrote: > That name sounds good to me. > > -- > 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+unsubscr...@googlegroups.com. > For more options, visit https://groups.google.com/d/optout. -- 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+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [racket-users] Raising arbitrary errors in Typed Racket
That name sounds good to me. -- 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+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [racket-users] Raising arbitrary errors in Typed Racket
Thank you, I have made my own exception type now. Is `exn:fail:rpc` appropriate or should I use a different name? Using that name looks like I'm inserting it into Racket's own exception type hierarchy. On Friday, December 1, 2017 at 8:11:27 PM UTC+1, Ben Greenman wrote: > > ... > -- 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+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [racket-users] Raising arbitrary errors in Typed Racket
The error is because type signature of `raise` doesn't allow "non-flat" values like functions and mutable vectors. It might not be safe to allow `(raise (vector 1 2 3))` in Typed Racket ... I'm not sure. For now I think you should make a new exception type. Example: ``` #lang typed/racket/base (define-type Packable (U Byte (Vectorof Packable))) (struct exn:fail:rpc exn ((val : Packable))) (with-handlers ((exn:fail:rpc? exn:fail:rpc-val)) (raise (exn:fail:rpc "oops" (current-continuation-marks) (vector 1 2 3 ``` On Fri, Dec 1, 2017 at 9:05 AM, HiPhishwrote: > Hello Racketeers, > > I have been trying to port a module over to Typed Racket, and I have almost > succeeded except for one issue: raising an arbitrary object as an error. > Compare the following code: > > ;; Works fine > (raise 3) > > ;; Does not work > (raise (vector 1 2 3)) > > The error I get is > ; nvim-client/client.rkt:244:55: Type Checker: No function domains > matched in > ; function application: > ; Domains: (U (Rec flat (U (Pairof flat flat) Boolean Char Complex > Keyword Null > ; String Symbol)) exn) Any > ; (U (Rec flat (U (Pairof flat flat) Boolean Char Complex > Keyword Null > ;String Symbol)) exn) > ; Arguments: (U (Immutable-HashTable Packable Packable) > (Mutable-HashTable > ; Packable Packable) (Pairof Packable (Listof Packable)) > (Weak-HashTable > ; Packable Packable) Boolean Bytes Ext Message-Args Null Real String) > ; in: (raise error) > ; [,bt for context] > > So I looked up the signature of `raise` and I get this: > > > raise > - : (->* ((U (Rec > flat > (U (Pairof flat flat) > Boolean > Char > Complex > Keyword > Null > String > Symbol)) > exn)) > (Any) > (Nothing : (Bot | Bot))) > # > > So what does this mean and what should I do? I am porting a module from my > Neovim client which uses the MessagePack-RPC protocol, and part of the > protocol > is that any object that can be packed can be raised as an error. > https://github.com/msgpack-rpc/msgpack-rpc/blob/master/spec.md#error > > Raising any object as an error would have allowed someone making an RPC > request > to just do something like this: > > (with-handlers ([packable? (λ (exn) (display exn))]) > (rpc-request "foo" '#(bar))) > > What should I do instead? Create a new error type like `exn:fail:rpc`? Or am > I > missing something here? > > -- > 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+unsubscr...@googlegroups.com. > For more options, visit https://groups.google.com/d/optout. -- 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+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
[racket-users] Raising arbitrary errors in Typed Racket
Hello Racketeers, I have been trying to port a module over to Typed Racket, and I have almost succeeded except for one issue: raising an arbitrary object as an error. Compare the following code: ;; Works fine (raise 3) ;; Does not work (raise (vector 1 2 3)) The error I get is ; nvim-client/client.rkt:244:55: Type Checker: No function domains matched in ; function application: ; Domains: (U (Rec flat (U (Pairof flat flat) Boolean Char Complex Keyword Null ; String Symbol)) exn) Any ; (U (Rec flat (U (Pairof flat flat) Boolean Char Complex Keyword Null ;String Symbol)) exn) ; Arguments: (U (Immutable-HashTable Packable Packable) (Mutable-HashTable ; Packable Packable) (Pairof Packable (Listof Packable)) (Weak-HashTable ; Packable Packable) Boolean Bytes Ext Message-Args Null Real String) ; in: (raise error) ; [,bt for context] So I looked up the signature of `raise` and I get this: > raise - : (->* ((U (Rec flat (U (Pairof flat flat) Boolean Char Complex Keyword Null String Symbol)) exn)) (Any) (Nothing : (Bot | Bot))) # So what does this mean and what should I do? I am porting a module from my Neovim client which uses the MessagePack-RPC protocol, and part of the protocol is that any object that can be packed can be raised as an error. https://github.com/msgpack-rpc/msgpack-rpc/blob/master/spec.md#error Raising any object as an error would have allowed someone making an RPC request to just do something like this: (with-handlers ([packable? (λ (exn) (display exn))]) (rpc-request "foo" '#(bar))) What should I do instead? Create a new error type like `exn:fail:rpc`? Or am I missing something here? -- 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+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.