1

I'm reading the Rosette Essentials.

The guide explains the use of define-symbolic:

The define-symbolic form binds the variable to the same (unique) [symbolic] constant every time it is evaluated.

(define (static)
 (define-symbolic x boolean?)  ; Creates the same constant when evaluated.
 x)

(define (dynamic)
 (define-symbolic* y integer?) ; Creates a fresh constant when evaluated.
 y)
 
> (eq? (static) (static))
#t

> (eq? (dynamic) (dynamic))
(= y$1 y$2)

Printed constant names, such as x or b, are just comments. Two [symbolic] constants created by evaluating two distinct define-symbolic (or, define-symbolic*) forms are distinct, even if they have the same printed name. They may still represent the same concrete value, but that is determined by the solver:

(define (yet-another-x)
 (define-symbolic x boolean?)
 x)

> (eq? (static) (yet-another-x))

(<=> x x)

I don't really understand the explanation of define-symbolic:

Why (eq? (static) (static)) returns #t, but (eq? (static) (yet-another-x)) returns (<=> x x)?

Since the define-symbolic binds the variable to the same (unique) constant every time it is evaluated, why (eq? (static) (yet-another-x)) does not return #t? , just like (eq? (static) (static))?

Does it mean that two symbolic variables occur in the different scope with the same name are still different, even if we use define-symbolic?

What's the difference between <=> and =? e.g. (<=> x x) vs (= y$1 y$2).

Thanks.

Will Ness
  • 70,110
  • 9
  • 98
  • 181
chansey
  • 1,266
  • 9
  • 20

2 Answers2

2

Here's an attempt to explain what the docs are saying:

  1. It matters which use of define-symbolic two different symbolic constants come from. So the two uses inside static and yet-another-x are different uses and thus different symbolic constants.

  2. It doesn't matter how many times you evaluate the same use of define-symbolic, it always produces the same symbolic constant. You can think of it as being hoisted out to the top-level of your program.

  3. For define-symbolic*, it does matter when you evaluate things, so (eq? (dynamic) (dynamic)) produces a constraint that might or might not be true, depending on what the solver says and what other constraints you add.

  4. = only works on numbers. <=> only works on booleans. In general eq? probably isn't what you want for these comparisons.

Sam Tobin-Hochstadt
  • 4,983
  • 1
  • 21
  • 43
1

As you notice, there's something going on here with regard to the scope, which is left entirely out of the docs, unspecified, not mentioned at all. Very unfortunate; extremely vague. Few more remarks could probably go a long way toward clarifying the situation; but we're left out forced to guess.

My guess is that the form (define-symbolic x boolean?) knows something about where it appears, and acts accordingly each time it (the form) is evaluated. In

(define (static)
 (define-symbolic x boolean?)  ; Creates the same constant when evaluated.
 x)

what is the scope of x? The only possible reading seems to me to be, that the call (define-symbolic x boolean?) creates a local binding inside static and sets it to the "symbolic constant" it (i.e. the call) creates. In normal Scheme these would still be different entities on each different invocation of static, of course. Rosette does its own thing here, evidently.

All we have is the docs (sans the sources of course), so we might as well just go by them.

As to what "symbolic constants" are, they seems closely related to Prolog's logical variables, but such that also know something about their own type (and probably more "constraints" or what have you).

So it looks like (static) becomes kind of a generator of a logical variable. It somehow knows about its internal binding, knows whether it is called for the very first time or not, and acts accordingly.

In short, just read it slowly and take it on faith. Nothing else to do, unless you're willing to study the sources.


Regarding (<=> x x) and (= y$1 y$2), these look like constraints. The guide calls them "symbolic expressions". The <=> most likely means "not equal" is described here as "the logical bi-implication of two boolean values", and the = means equality. x, x, y$1 and y$2 are printed representations of the four different symbolic constants.

Two different symbolic constants can be known (required) to be (eventually) equal, as with the second constraint; or to be not equal, as with the first.

While they (the constants) don't yet have any concrete value associated with them the constraint remains symbolic; but it can be actually checked as soon as the symbolic constant/logical variable gets its concrete value (or possibly gets more constraints associated with it, so those constraints could in theory be checked for consistency).

Will Ness
  • 70,110
  • 9
  • 98
  • 181
  • About `<=>`, see the docs https://docs.racket-lang.org/rosette-guide/sec_bools_ints_reals.html?q=%3C%3D%3E#%28def._%28%28lib._rosette%2Fbase%2Fbase..rkt%29._~3c~3d~3e%29%29 It seems more like a "equal" constraint rather than a "not equal" constraint, but I have no idea whether `<=>` and `=` are the same thing. – chansey Jul 19 '21 at 12:59
  • I just realized that the `<=>` only be used for `boolean?`. The `<=>` may be `=` for `boolean?`. – chansey Jul 19 '21 at 12:59