Can Racket programs be modified at run time?

I was thinking about how to write gui programs whose behaviors and features could be modified by beginner programmers and non-programmers. I think scheme would be a great language for this as it's much smaller than a lot of other programming languages and has a simple syntax to learn. For non-programmers who didn't want to learn a large language or use scheme, they might benefit from a more a declarative language like SQL. Therefore, in my mind a program written in Racket that could be extended with a declarative language (also written in Racket) seems like a perfect fit. The declarative language would be the gateway, and if the non-programmer ever transitioned to hobby programmer in an effort to do something more complex, then diving into the actual Racket code would hopefully be not too much of a cognitive leap. For the individual who is a beginning programmer that has some experience in another language, or who has the motivation to work with the language the hypothetical declarative language compiles down to, might want to start extending the program with Racket instead.

Examples of how this declarative language could be used are...

  1. To extend a file browser with a more complicated sorting logic than the default date modified, size, type and name filters. (Good for someone with lots of pictures or music)

  2. To set a text editor to read only mode when accessing files located in specific folders containing critical configuration criteria

  3. To extend a desktop to change background wallpapers based on the time of day or current season.

The problem space is tasks that would be difficult to complete just by modifying options in the configuration menu but would be simple to solve in code. The only problem is, I'm not sure if the immutable top level would get in the way of this if you were using Racket? There are plenty of examples of C programs (a language that can't be modified at run time) extended with an extension language that gives the C program more dynamic capabilities. Could this be done just using Racket and a Racket #lang? Or would it require modification to the Racket compiler to support this feature? It would be a shame if it couldn't be done as I feel Racket fits most of the bill when it comes to developing this type of solution

You might be interested in @bogdanp's work on a scriptable GUI via #lang lua (I can't find any of the references I thought I had, now, but IIRC the GUI was for a kafka client or manager).

1 Like

I think there are a few distinct questions here.

  1. Can Racket programs be modified at run time?

    Sure. Even C programs can be modified at runtime, e.g. using dlopen to load plugins. There are lots of ways to modify programs at runtime.

  2. Can Racket be used in a style like Lisps that allow (set! + -)?

    You didn't explicitly ask this question, but I think it's what you had in mind when asking question 1.

    It would take effort, but there are ways to do at least parts of it. The reloadable package is a principled way. You could easily define a language where #%module-begin uses local-expand to get a fully expanded program, then transform every (define-values [a ...+] expr) to (begin (define-values [a ...] expr) (set! a a) ...). As a last resort, there's compile-enforce-module-constants.

    But …

  3. The only problem is, I'm not sure if the immutable top level would get in the way of this if you were using Racket?

    The immutable top level would not get in the way of what you've described, so there's no need to work around it.

Let's consider this example:

To extend a file browser with a more complicated sorting logic than the default date modified, size, type and name filters. (Good for someone with lots of pictures or music)

My file manager, KDE Dolphin, has sortable columns like this:

Let's can imagine a button to add a new kind of possible column: clicking it would open a dialog with a text input field in which we might write something like this (inspired by sort):

#lang file-manager/column-plugin
(define name
  "Date")
(define less-than? moment<?)
(define (extract-key file)
  (cond
    [(image-file? file)
     (image-file-exif-date file)]
    [(audio-file? file)
     (audio-file-id3-date file)]
    [else
     (file-mtime file)]))

When we click the Apply button, the file manager reads and evals what we've written and adds a column type accordingly. No mutation needed!

1 Like