> On Dec 1, 2016, at 21:43, David Storrs <david.sto...@gmail.com> 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.