
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