I've seen the idiom
(struct unique-value ())
to create unique values, for example as default arguments in a function to check with (eq? argument unique-value)
if anything was passed for the argument.
Since I have only little experience with Racket macros so far, I took this as a motivation to define a macro around this. (But in the end, because of the helper function, the macro itself turned out much simpler than I had expected.) To be useful to as many readers as possible I added comments more extensively than I usually do, even though I certainly learned a lot myself and therefore had added some of the comments anyway.
#lang racket/base
(require
racket/format
racket/function)
; Define a helper function `make-unique-value` to generate
; a value of a struct (that only exists locally).
;
; Note that we must return a value of the struct, not
; the struct (`unique-value`) itself because otherwise the
; custom write method isn't applied.
(define (make-unique-value name)
(struct unique-value ()
; See https://docs.racket-lang.org/reference/define-struct.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._struct%29%29
; and https://docs.racket-lang.org/reference/Printer_Extension.html#%28def._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._gen~3acustom-write%29%29
#:methods gen:custom-write
; Pre-set the name as the rightmost argument because
; the function for `write-proc` must use three arguments,
; but we need to get the name somehow into `write-proc`.
[(define write-proc (curryr unique-value-write name))])
(unique-value))
(define (unique-value-write unique-value port mode name)
(write-string (~a "#<unique:" name ">") port))
; Test the helper function.
(define foo (make-unique-value "foo"))
; #<unique:foo>
(displayln foo)
; Macro that wraps the helper function and allows us to use
; the syntax `(define-unique name)`.
;
; To convert the new identifier name to something that can be
; processed in the helper function, use `quote` to convert the
; name to a symbol, see
; https://rmculpepper.github.io/malr/basic.html .
(define-syntax-rule (define-unique name)
; Strictly speaking, we don't need `symbol->string` here
; because the custom write function formats 'name exactly
; like "name", but let's be clear on the intended types.
(define name (make-unique-value (symbol->string (quote name)))))
(define-unique bar)
; #<unique:bar>
(displayln bar)
I wouldn't be surprised if this existed already in a package or even the standard library, but I wanted to experiment with this.