Re: [racket-users] Advantage of ->d over ->i

2017-12-01 Thread Philip McGrath
On Fri, Dec 1, 2017 at 10:08 PM, Ben Greenman 
wrote:

> 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

2017-12-01 Thread Ben Greenman
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

2017-12-01 Thread Philip McGrath
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

2017-12-01 Thread Robby Findler
Why not use any-wrap/c?

Robby

On Fri, Dec 1, 2017 at 8:39 PM Sam Tobin-Hochstadt 
wrote:

> 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

2017-12-01 Thread Sam Tobin-Hochstadt
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.


Re: [racket-users] Raising arbitrary errors in Typed Racket

2017-12-01 Thread Ben Greenman
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

2017-12-01 Thread HiPhish
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

2017-12-01 Thread Ben Greenman
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, HiPhish  wrote:
> 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

2017-12-01 Thread HiPhish
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.