Universal?
By “universal”, I meant contracts made with #:forall or new-∀/c.
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 has joined the channel
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.
It’s certainly the case that the restricted form of map with only one list could have a parametric contract.
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.
Hi, I have a question about continuations
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
@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).
…hmm, that makes it fail during creation… returning only one value (a pict) for val1 and cont1. So it misses the abort-cc
FWIW here you can see the difference between dc and unsafe-dc: https://github.com/racket/pict/blob/d88cd6d3ffe0e5eb72dc799a823f255a27ae52da/pict-lib/pict/main.rkt#L99
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))
thanks
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.
@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
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
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