Search code examples
data-structuresracket

Create a Racket prop:custom-write that prints like #:transparent


I have written the following struct definition:

> (require racket/struct)
> (struct/contract foo
    ([bar (listof number?)])
    #:property prop:custom-write
    (make-constructor-style-printer
      (lambda _ 'fiz)
      (lambda (self) (list (map add1 (foo-bar self))))))

When I print an instance, it seems at first to print fine, but when I put that instance into a list, it prints surrounded by #< ... >:

> (foo '(1 2 3))
(fiz '(2 3 4))
> `(,(foo '(1 2 3)))
'(#<fiz: (2 3 4)>)

What I would expect to happen is for it to print like the struct below:

> (struct/contract biz
    ([bar (listof number?)])
    #:transparent)
> (biz '(1 2 3))
(biz '(1 2 3))
> `(,(biz '(1 2 3)))
(list (biz '(1 2 3)))

What am I doing wrong?


Solution

  • From the documentation of make-constructor-style-printer:

    Note that the printer uses a separate property, prop:custom-print-quotable, to determine whether a struct instance is quotable. If so, the printer may print it in write mode it in certain contexts, such as within a list.

    So you need to set the prop:custom-print-quotable property too to get the behavior you're looking for:

    (struct/contract foo
     ([bar (listof number?)])
     #:property prop:custom-write
     (make-constructor-style-printer
      (lambda _ 'fiz)
      (lambda (self) (list (map add1 (foo-bar self)))))
     #:property prop:custom-print-quotable 'never)
    

    Examples of use:

    > (define x (foo '(1 2 3))
    > (list x) ; uses print
    (list (fiz '(2 3 4)))
    > (writeln (list x)) ; write isn't affected
    (#<fiz: (2 3 4)>)