soegaard2
2020-10-11 12:45:22

Universal?


kellysmith12.21
2020-10-11 13:05:18

By “universal”, I meant contracts made with #:forall or new-∀/c.


kellysmith12.21
2020-10-11 13:24:45

My question wasn’t well-worded. Another way of putting would be: is there a reason why map shouldn’t have a contract that’s similar to the type that it would have in a statically-typed setting?


taiga.k.5884
2020-10-11 15:09:51

@taiga.k.5884 has joined the channel


camoy
2020-10-11 16:21:06

One reason is Racket’s map has variable arity. So if you provided k lists you’d need k+1 universal contracts. I don’t think it’s very straightforward to write that.


camoy
2020-10-11 16:27:13

It’s certainly the case that the restricted form of map with only one list could have a parametric contract.


camoy
2020-10-11 16:41:19

One the last thing: In the case of a parametric contract on map, you’re only imposing a check on the library side, not on the client side. Since map is pretty well battle-tested it’s unlikely to ever be raised in practice. That’s fine if the contract is cheap and conveys useful information. But in this case there’s the expense of allocation of opaque wrappers for every element of the inputs and outputs. It’s a trade off and might not be worth it.


bedeke
2020-10-11 17:31:16

Hi, I have a question about continuations


bedeke
2020-10-11 17:31:32

a lot of strange things are happening with the interaction between pict’s dc and my continuation. I expected test1(pict) to be more or less in line with test0(+) but I’m clearly not understanding the finer details. Could someone explain the observed behavior?

#lang racket/base (require pict racket/gui/base racket/control) ;*********************************************** (define (save-for-later! v) (call-with-composable-continuation (lambda (k) ; k is the captured continuation (abort-current-continuation (default-continuation-prompt-tag) (λ () (values v k)))))) ;*********************************************** (displayln "test0: creation") (define-values (val0 cont0) (prompt (apply (λ (x) (+ x (+ (begin (displayln 0) 1) (+ 1 (save-for-later! "hallo"))))) '(1)))) (displayln "test0: call") val0 ;; "hallo" (cont0 5) ;; 8 (newline) ;*********************************************** (displayln "test1: creation") (define-values (val1 cont1) (prompt (dc (λ (dc-inst x y) (displayln 0) "whatever" (save-for-later! dc-inst)) 100 100))) (displayln "test1: call") val1 ;; (wrapper-object:bitmap-dc% ...) ;; so far everything is as I expected, but starting from here... (cont1) ;; ->only shows the zero from displayln (again) ;; from here on, all other lines are ignored in drracket (/ 1 0) ;; writing following in the REPL: (define b (cont1)) b ;; makes b a pict?, but a very strange one: it is 3 lines, ;; first the displayed 0 (purple) ;; second and third the values of val1 and cont1 (blue) (show-pict b) ;; this fails at the cli with: ;0 ;; <= note the extra 0... ;result arity mismatch; ; expected number of values not received ; expected: 1 ; received: 2 ; values...: ; (wrapper-object:dc% ...) ; #<continuation> ;; but it works in the REPL, just showing b as above. (vl-append 100 b b) ;; shows the same as b


soegaard2
2020-10-11 17:45:16

@bedeke To keep things simple (well, simpler) try unsafe-dc instead. The draw routine is called twice (one from the contract and then the ordinary call).


bedeke
2020-10-11 17:52:17

…hmm, that makes it fail during creation… returning only one value (a pict) for val1 and cont1. So it misses the abort-cc


soegaard2
2020-10-11 17:57:46

soegaard2
2020-10-11 17:58:05

The contract calls: (define (does-draw-restore-the-state-after-being-called? draw) (define bdc (new bitmap-dc% [bitmap (make-bitmap 1 1)])) (prandomize-state bdc) (define old-state (get-dc-state bdc)) (draw bdc 0 0) (equal? (get-dc-state bdc) old-state))


bedeke
2020-10-11 17:58:56

thanks


rokitna
2020-10-12 02:27:47

I’m pessimistic, but I’m hoping you get a positive answer. In the meantime, I’ve come up with one idea that might help:

You might be able to create an all-new structure type property to be a more expressive version of prop:dict and make the old prop:dict a simple façade for the new one (by using the supers argument to make-struct-type-property).

You don’t even have to expose the new one to users. The dict/c contract would create an instance of the new property directly, and the dict? predicate could check for the new property instead of the old one (so that it recognizes the chaperones dict/c creates), but users could still do all their instance creation via prop:dict and gen:dict.


alexknauth
2020-10-12 04:37:08

@rokitna > The dict/c contract would create an instance of the new property directly Thanks for the suggestion, but I’m not sure how to make that work as chaperone… you see I’m not actually creating new structs with prop:dict anymore (I did that in an old version that had to be an impersonator contract), instead I’m using redirect-generics to wrap existing structs that already implement the interface. This allows the value produced by the projection to be a chaperone-of the original value, which means it’s the same struct-type with the same struct-type-properties as the original.

However the idea of using struct-type-property inheritance is still intriguing… if I could force gen:dict to delegate to a new property, and then redirect that new property instead? But users write their own method implementations so I don’t know how I could force it to delegate to a new property like that


alexknauth
2020-10-12 04:58:09

Ok I just got a crazy idea but it feels kind of evil:

Use #:fast-defaults to make sure gen:dict’s dict-ref always delegates to prop:new-dict, overriding whatever implementation the user gave. Then have prop:new-dict delegate to prop:dict, bypassing the #:fast-defaults to get to the user’s implementation.

When gen:dict’s dict-ref delegates to prop:new-dict, it wraps non-procedure failure-results in procedures, so that prop:new-dict always gets a procedure failure-result. Then dict/c can redirect prop:new-dict and know it will always be a procedure


alexknauth
2020-10-12 05:03:40

Or maybe I can skip a step and use #:fast-defaults to force gen:dict’s dict-ref to delegate to prop:dict while making the failure-result a procedure