
Thank you for the cool 7.1 release! Specially: > (define (add #:x x #:y y) (+ x y))
> (define add1 (curry add #:x 1))
> (add1 #:y 2)
3
Really neat! Thx!

Is there a way to declare package dependencies so that something like raco install
would install all the necessary dependencies? Like Anaconda environments.

@contact yes, you declare dependencies in the info.rkt file

Great thx!

I think you’d have to ask @robby or maybe @dan

It affects contract-blame

If you are making a combinator, you can use it to stick blame onto something so that contract-blame
will return it. It is on you (as the combinator author) to get that right.

@contact if you want to avoid manually specifying dependencies, raco setup
has an option to automatically detect missing dependencies and write them to the correct package’s info.rkt file.
There’s a concise tutorial that has useful details http://blog.racket-lang.org/2017/10/tutorial-creating-a-package.html

Great! Will take a look. Thx!

I don’t see a contract-blame
function in the docs

@vibhavp has joined the channel

Hello, is the Racket VM’s bytecode instruction set documented anywhere?

Oops, object-blame

Uhhh value-blame?

It answers only the question “who might get blamed if I use this value”. There are no other guarantees

I think value-blame
queries it. I had thought value-blame
might be used in the contract-profiler, but I’m not sure about that.
I don’t think it changes the error messages anywhere, and it’s just a convenient place to store the blame information on a contracted value in case some tool needs to use that information

Are there tools that use it? Why would a tool want to use it?

@macocio has joined the channel

@robby In the test suite for the contract system, is there a contract I can use if I want to test that something works with a (conjoin contract? (negate chaperone-contract?))
? Testing against any of the built-in contracts that happen to currently produce non-chaperone contracts (such as, for example, class contracts) seems like a bad idea, since they could always be improved to produce chaperone contracts in the future.

An impersonator contract?

Right. I’m wondering if there’s a canonical impersonator contract that is guaranteed to not become a chaperone contract at some point in the future.

@lexi.lambda you can just write your own with make-contract unless I’m misunderstanding?

parametric/c
generates impersonator contracts that have to be that way

@dan Yes, I can do that if that’s the right answer, I was just wondering if there was something else the test suite did something else by convention.

@samth That’s a good point!

I don’t think I can really use parametric contracts here, though, since I’m putting a contract on an immutable data structure, which doesn’t really have a meaningful way to use parametric contracts… though I guess I could write a function on the immutable data structure, instead.

(Also, I only just noticed impersonator-contract?
exists; I find it a little weird that flat-contract?
appears to imply chaperone-contract?
but impersonator-contract?
is its own thing.)

@lexi.lambda I’ve had issues with these distinctions before too because I think there are at least two reasonable views: 1. There’s a hierarchy and all flat contracts are also chaperones, and all chaperone contracts are impersonators, but some impersonators are neither flat nor chaperone 2. The categories are disjoint, so flat is distinct from chaperone which must wrap and preserve behavior bs impersonators with no guarantees.
I think the predicates that recognize these things have ended up somewhere in the middle of these two so it’s sort of confusing, although I think impersonator-contract?
is roughly equivalent to not flat and not chaperone

There’s also the additional point of confusion that chaperone-contract?
recognizes contracts whose projections must produce values that satisfy chaperone-of?
, but impersonator-contract?
projections do not have to preserve impersonator-of?
.

I have discovered something that must point to a misunderstanding on my part. The first function behaves as I’d expect. What’s going on with the second function?
(if (or (not x) (equal? y 'surprise))
'invalid
y))
> (check #t 'surprise)
'invalid
(parametric->/c [X] (boolean? X . -> . X))
(if (or (not x) (equal? y 'surprise))
'invalid
y))
> (check #t 'surprise)
'surprise

@paul The second function wraps y into a #<X> value so you can’t really do anything with it, see https://docs.racket-lang.org/reference/parametric-contracts.html?q=parametric-%3E%2Fc#%28form._%28%28lib._racket%2Fcontract%2Fparametric..rkt%29._parametric-~3e%2Fc%29%29

@macocio Yes, I read the description. I don’t have a good grip on wrappers yet. But is the mere presence of a contract supposed to change the evaluation of the if
form? Why does (check #t 'surprise)
evaluate differently with the contract?

@paul Speaking of 'surprise
s and equal?
: The doc for equal?
mentions it works for “inspectable structures”. Well, Racket struct
s are by default opaque — not inspectable. Only #:transparent
(or #:prefab
) struct
s can be equal?
. This sometimes catches people by surprise (where “people” includes me in the past, and other people I’ve talked to.)

@paul because (equal? 'surprise #<X>)
=> #f, so it returns y

@paul The mere presence of a chaperone or flat contract is not supposed to change semantics in ways like that. However, impersonator contracts can pretty much do whatever they want. Most contracts are flat or chaperone. As far as I know, parametric contracts are the only use case for impersonator contracts.

So a good rule of thumb is that as long as you’re not using parametric contracts, you won’t run into impersonators and contracts won’t change how equal?
works

Wow! I must do more reading on contracts. So does this mean that the following documentation ought to be reworked not to use equal?
? Or should a sentence or two be added to explain what is going on? It sure fooled me.

I think what the docs were trying to explain with that example is that parametric->
is supposed to change how equal?
works, because a parametric function isn’t supposed to do anything with the inputs its parametric in. This includes inspecting them with equal?
.

It’s a bit weird that the docs for parametric->/c
have an example of how not to use it without first presenting an example of how you’re supposed to use it correctly.

it should probably be (X . -> . (listof X))
to indicate that the focus is on the types, not the code within… that parametric types aren’t supposed to be “used” by the function since it lacks type information.

ofc change the fn appropriately to fit that contract

If you’re looking to improve those docs, I’d fix that. After the current two paragraphs of prose add an example of a good use of parametricity like this:
(define/contract (choose-one bool a b)
(parametric->/c [X] (boolean? X X . -> . X))
(if bool a b))

I don’t think talking about it in terms of types will be helpful; parametric contracts have some very big differences from a parametrically polymorphic type variable

@notjack I like that example, I’d also like to show readers how to use them in type constructors (define/contract (cons-same x lst)
(parametric->/c [X] (X (listof X) . -> . (listof X))
(cons x lst))

The way parametric contracts work is if a function promises that it doesn’t care what input it’s given, the parametric contract says “okay prove it” by wrapping every input as it goes into the function so all the function sees is this black box value that it can’t do anything with. It’s deliberately not equal?
to any other value.

I say type ctors but it’s probably called something different in racket. This is maybe useful for more haskell-oriented people I guess

If a function says it doesn’t care about its input, but then actually tries to peek at the input by testing it with equal?
or do something else with it (like log it), the opaque wrapper causes that to fail

Then I have to say that the example in the documentation now, without any explanation, feels like a deliberate trap. Where can I read about these wrappers that explains what y’all have just explained to me?
I’m not sure I’m ready to update the documentation. Should I add an issue and then hopefully come back to it in the future and deal with it myself?

I think an issue would be great

Hmm. There’s a section in the racket guide on parametric contracts: https://docs.racket-lang.org/guide/contracts-exists.html

but it’s not linked from the reference section

and it doesn’t cover parametric->/c

I think the only place this is thoroughly discussed is the paper on parametric contracts

For debugging purposes, can we extract information out of the opaque object?

ah hah! found the paper


wait nope


Okay I found the paper I was thinking of. It’s “Relationally-Parametric Polymorphic Contracts”: https://www.eecs.northwestern.edu/~robby/pubs/papers/dls2007-gmfk.pdf

> “Informally, if a function f
accepts an argument of type α
, parametricity ensures that the argument is abstract to f
— the argument may not be examined or deconstructed by f
in any way. Moreover, f
may not determine the concrete type of α
. This seemingly harsh restriction in fact allows rich abstractions. Since values of type α
are abstract to f
, a programmer may change the concrete type of α
and be assured that the behavior of f
will not change. Therefore, we want contracts of the form (forall (α ...) C)
to preserve the static notion of parametric polymorphism at runtime. Such contracts will implement—that is to say, detect violations of—relational parametricity.”
@paul Does this prose help?

@macocio I don’t think so. If you try to log it it just prints as something like #<opaque>