Re: [racket-users] Syntax for hash contracts

2016-12-02 Thread Ben Greenman
On Thu, Dec 1, 2016 at 7:29 PM, David Storrs  wrote:

> I'm having trouble understanding the docs on hash contracts (
> https://docs.racket-lang.org/reference/data-structure-
> contracts.html#%28def._%28%28lib._racket%2Fcontract%
> 2Fprivate%2Fhash..rkt%29._hash%2Fc%29%29)
>
> What I'm trying to express is:
>
> - This function returns #t because it is a simple test function intended
> to get the hang of hash contracts...
> - This function takes one argument...
> - Which is a hash...
> - Which has keys 'success, 'file-id, 'scratchdir-path, and 'chunk-hash...
> - All of which are symbols...
> - The values will be, respectively:
> success boolean?
>

1. Like Alexis says, `hash/dc` lets you specify a relationship between keys
and values **but** the same relationship needs to hold for every key/value
pair. Here's an example:

#lang racket
(require rackunit)

(define my-hash/c
  (hash/dc [k char?] [v (k) (=/c (char->integer k))]))

(contract my-hash/c (make-hash '((#\A . 65) (#\B . 66))) '+ '-)
;; good hash

(contract my-hash/c (make-hash '((#\A . 66))) 'pos 'neg)
;; bad hash


2. And here's a funny way to check the property you care about

(define special-list/c
  (list/c (cons/c 'chunk-hash string?)
  (cons/c 'file-id (or/c #f exact-positive-integer?))
  (cons/c 'scratchdir-path path-string?)
  (cons/c 'success boolean?)))

(define (special-hash/c h)
  (special-list/c (sort (hash->list h) symbolhttps://groups.google.com/d/optout.


Re: [racket-users] Syntax for hash contracts

2016-12-01 Thread David Storrs
On Thu, Dec 1, 2016 at 10:18 PM, Alexis King  wrote:

> > On Dec 1, 2016, at 21:43, David Storrs  wrote:
> >
> > The difference between a dictionary and a structure being that
> dictionaries are easily extensible on the fly and structures are not?  I'm
> curious -- what are the elements of that design and what are the reasons?
> It seems like a natural fit -- if Racket supported contracts on the values
> of a contract then you would have the best of dictionaries and structures.
>
> The difference is that a structure has intrinsic meaning while a hash
> with a particular collection of keys has extrinsic meaning.[...] Racket in
> general heavily favors custom, tagged data over reusing
>
data structures


Fair enough.  I come from a Perl background and am used to a slightly more
relaxed system, but I'll try to get used to the new way.


>
> > Hm.  Well, that approach would work.  It's not really what I'm looking
> for, though -- this is data that's coming back from a SQL query and being
> forwarded on to another function for further processing.  It isn't needed
> anywhere else, and creating a struct for this one use feels pretty clumsy
> and heavyweight.  "Hash of field-name-in-table to value-in-field" seemed
> like a really intuitive solution.  It's fine, though.  I can just do a
> manual check.
>
> If you are just handing off this data between two functions as an
> implementation detail, do you need the contract at all? That is, what
> value are you getting from it? Could the arguments be provided as
> keyword arguments, instead?
>

That's a good thought.  Yes, that will work.  I had them as a hash because
I used them in the source function and it was convenient to have them that
way, so I figured I could just hand them off to the sub-function in the
original hash form.  Better to split it up though, I suppose.



> That said, if you wanted a contract that does what you describe, it
> wouldn’t be too difficult to write:
>
>   (define (hash-object/c ctc-dict)
> (make-contract
>  #:name `(hash-object/c
>   ,(for/list ([(k v) (in-dict ctc-dict)])
>  (cons k (contract-name v
>  #:projection
>  (λ (blame)
>(λ (val)
>  (for ([(k v) (in-hash val)])
>(let ([ctc (dict-ref ctc-dict k #f)]
>  [blame (blame-add-context
>  blame (format "value for key ~e of" k))])
>  (when ctc
>(((contract-projection ctc) blame) v
>

...I think your definition of "not too hard" may differ from mine.  :>


> The existing hash contracts are mostly designed to accommodate
> homogenous dictionaries, like (hash/c string? boolean?). I’m not
> entirely sure what the intended use case of hash/dc is, and while I’m
> sure I’d be very glad it exists if I ever needed it, I admit I’ve never
> used it myself. It just allows you to provide a function that determines
> the contract of a value given the key, but it still requires that all
> keys have the same contract, and it does not let you specify which keys
> should be supplied.
>

Okay, that makes more sense.  Thanks for all the explanation.



>
> --
> 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] Syntax for hash contracts

2016-12-01 Thread Alexis King
> On Dec 1, 2016, at 21:43, David Storrs  wrote:
> 
> The difference between a dictionary and a structure being that dictionaries 
> are easily extensible on the fly and structures are not?  I'm curious -- what 
> are the elements of that design and what are the reasons?  It seems like a 
> natural fit -- if Racket supported contracts on the values of a contract then 
> you would have the best of dictionaries and structures.

The difference is that a structure has intrinsic meaning while a hash
with a particular collection of keys has extrinsic meaning. One could
represent a point in two-dimensional space as a struct called “point” or
a hash with keys 'x and 'y. The former is intrinsically a point, but the
latter is only a point if you use it like a point; it could just as
easily be a two-dimensional vector (which itself has a myriad of
possible meanings).

Put more practically, structs are tagged, and hashes are untagged. This
might not seem terribly important in your case (and it probably isn’t),
but Racket in general heavily favors custom, tagged data over reusing
data structures, in contrast with Clojure, which takes precisely the
opposite approach. (The design differences between Racket’s contract
combinators and the recent clojure.spec illustrate much of this
difference in philosophy.) I’m sure there are many other people on this
list who can describe the reasoning behind Racket’s design choices here
far better than I can, so I will not try at this time.

> Hm.  Well, that approach would work.  It's not really what I'm looking for, 
> though -- this is data that's coming back from a SQL query and being 
> forwarded on to another function for further processing.  It isn't needed 
> anywhere else, and creating a struct for this one use feels pretty clumsy and 
> heavyweight.  "Hash of field-name-in-table to value-in-field" seemed like a 
> really intuitive solution.  It's fine, though.  I can just do a manual check.

If you are just handing off this data between two functions as an
implementation detail, do you need the contract at all? That is, what
value are you getting from it? Could the arguments be provided as
keyword arguments, instead?

That said, if you wanted a contract that does what you describe, it
wouldn’t be too difficult to write:

  (define (hash-object/c ctc-dict)
(make-contract
 #:name `(hash-object/c
  ,(for/list ([(k v) (in-dict ctc-dict)])
 (cons k (contract-name v
 #:projection
 (λ (blame)
   (λ (val)
 (for ([(k v) (in-hash val)])
   (let ([ctc (dict-ref ctc-dict k #f)]
 [blame (blame-add-context
 blame (format "value for key ~e of" k))])
 (when ctc
   (((contract-projection ctc) blame) v

This contract is not terribly robust or performant (it should ensure the
value is immutable, use the late negative projection and do more work
ahead of time, etc.), but it’s a demonstration of the behavior you want.
You could use it like this:

  (define/contract h
(hash-object/c `([foo . ,string?]
 [bar . ,boolean?]))
(hash 'foo "hello" 'bar #f))

> So, given that these don't work the way I thought, how DO they work?  I still 
> can't understand this documentation -- like, literally *at all*.  I have not 
> managed to write a single non-trivial contract thus far.  Could you please 
> provide some examples of how to use hash contracts and why?
> 
> For example, I don't see how to do something as simple as "this hash must 
> have the following keys".  Or how to say that some keys will be of different 
> types -- e.g., 'foo and "bar".

The existing hash contracts are mostly designed to accommodate
homogenous dictionaries, like (hash/c string? boolean?). I’m not
entirely sure what the intended use case of hash/dc is, and while I’m
sure I’d be very glad it exists if I ever needed it, I admit I’ve never
used it myself. It just allows you to provide a function that determines
the contract of a value given the key, but it still requires that all
keys have the same contract, and it does not let you specify which keys
should be supplied.

-- 
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] Syntax for hash contracts

2016-12-01 Thread David Storrs
On Thu, Dec 1, 2016 at 8:59 PM, Alexis King  wrote:

> > On Dec 1, 2016, at 16:29, David Storrs  wrote:
> >
> > - This function returns #t because it is a simple test function intended
> to get the hang of hash contracts...
> > - This function takes one argument...
> > - Which is a hash...
> > - Which has keys 'success, 'file-id, 'scratchdir-path, and 'chunk-hash...
> > - All of which are symbols...
> > - The values will be, respectively:
> > success boolean?
> > file-id (or/c #f exact-positive-integer?)
> > scratchdir-path path-string?
> > chunk-hash string?
>
> The hash/dc contract is not designed to assign contracts to the values
> associated with specific keys; rather, it allows the contract on a value
> to depend generally on the value of the key. You could theoretically use
> the right hand side of the contract to do a case analysis on the value
> of the key, but that would not be pretty. This is mostly intentional,
> though: Racket hashes are designed to be used as dictionaries, not
> structures.
>

The difference between a dictionary and a structure being that dictionaries
are easily extensible on the fly and structures are not?  I'm curious --
what are the elements of that design and what are the reasons?  It seems
like a natural fit -- if Racket supported contracts on the values of a
contract then you would have the best of dictionaries and structures.

(I'm worried that the above sounds snarky, but I'm not sure how to rephrase
it  It's not intended as snark, it's an honest question.)


>
> It sounds like you likely want a struct, not a hash. Probably something
> like this:
>
>   (struct some-name (success file-id scratchdir-path chunk-hash))
>
> …with the following contract:
>
>   (struct/c some-name
> boolean?
> (or/c #f exact-positive-integer?)
> path-string?
> string?)
>
>
Hm.  Well, that approach would work.  It's not really what I'm looking for,
though -- this is data that's coming back from a SQL query and being
forwarded on to another function for further processing.  It isn't needed
anywhere else, and creating a struct for this one use feels pretty clumsy
and heavyweight.  "Hash of field-name-in-table to value-in-field" seemed
like a really intuitive solution.  It's fine, though.  I can just do a
manual check.


So, given that these don't work the way I thought, how DO they work?  I
still can't understand this documentation -- like, literally *at all*.  I
have not managed to write a single non-trivial contract thus far.  Could
you please provide some examples of how to use hash contracts and why?

For example, I don't see how to do something as simple as "this hash must
have the following keys".  Or how to say that some keys will be of
different types -- e.g., 'foo and "bar".


--
> 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] Syntax for hash contracts

2016-12-01 Thread Alexis King
> On Dec 1, 2016, at 16:29, David Storrs  wrote:
> 
> - This function returns #t because it is a simple test function intended to 
> get the hang of hash contracts...
> - This function takes one argument...
> - Which is a hash...
> - Which has keys 'success, 'file-id, 'scratchdir-path, and 'chunk-hash...
> - All of which are symbols...
> - The values will be, respectively:
> success boolean?
> file-id (or/c #f exact-positive-integer?)
> scratchdir-path path-string?
> chunk-hash string?

The hash/dc contract is not designed to assign contracts to the values
associated with specific keys; rather, it allows the contract on a value
to depend generally on the value of the key. You could theoretically use
the right hand side of the contract to do a case analysis on the value
of the key, but that would not be pretty. This is mostly intentional,
though: Racket hashes are designed to be used as dictionaries, not
structures.

It sounds like you likely want a struct, not a hash. Probably something
like this:

  (struct some-name (success file-id scratchdir-path chunk-hash))

…with the following contract:

  (struct/c some-name
boolean?
(or/c #f exact-positive-integer?)
path-string?
string?)

-- 
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.