Renato
Renato

Reputation: 13690

How to redefine a standard function within a scope in Racket?

I would like to redefine a standard Racket function, namely display, within a lexical scope, as in this example:

(with-custom-display (display "hello"))

This should work even when the code within the scope of with-custom-display is from a different library or even racket/* packages.

Is this possible? If so, how to do it?

EDIT:

If not possible in general, at least for the case of display and other write functions... could I somehow transform every output by parameterizing on current-output-port then redirecting the transformed output to the original port?

Upvotes: 2

Views: 747

Answers (1)

Leif Andersen
Leif Andersen

Reputation: 22332

While its not possible1 to globally replace arbitrary functions in Racket, you absolutely CAN change the standard out port that a Racket program uses (and by extension, functions like display). In fact, this is exactly what the readline collection in racket does, except for input ports rather than output ports.

Basically, all you need to do is parameterize current-output-port globally to be your special port. Since you want to ultimately write out to the original output port (but with colors), you can also grab the original output port before changing it to the new one. Your resulting code would look something like this:

#lang racket/base ;; init.rkt
(define orig-port (current-output-port))
(define new-output-port
   .... uses orig-port ....)
(current-output-port new-ouput-port)

(replacing .... uses orig-port .... with the implementation of your new colored output port)

And now, any file that requires "init.rkt" will get color in its default output port.

(Note though that if you have multiple files that do this same sort of thing, you have to be careful to make sure that they don't happen in an unsafe order.)

You can also make your with-custom-display form as a simple language extension by doing:

#lang racket ;; custom-disp.rkt
(provide with-custom-display)
(require syntax/parse/define)
(define orig-port (current-output-port))
(define new-output-port
   .... uses orig-port ....)
(define-simple-macro (with-custom-display body ...)
  (parameterize ([current-output-port new-output-port])
    body ...))

This is the general idea of how DrRacket is able to print output to a DrRacket specific repl, rather than your consoles stdout.

1Normally anyway, there are usually ways to break things if you really want to. But that's almost always a bad idea. ;)

Upvotes: 2

Related Questions