Skip to content
Stephen De Gabrielle edited this page Jun 5, 2023 · 1 revision

Q. Is there a technical barrier to implementing an alternative (not a replacement) REPL that supports iterative redefinition?

@soegaard answered

Anything is possible in the land of macros.

One of the examples mentioned, where redefintions could be useful are games. You start the game (and at the same time have a repl) and play for 10 minutes and notice something, you want to change. Being able to make the change on-the-fly seems convenient.

Making everything redefinable is not the only answer though.

That said, below is a quick version of redefine. It's simple, very simple - so don't expect too much. Avoid using it for local definitions.

#lang racket
;;;
;;; Redefine
;;;

;; SYNTAX  (redefine id expr)
;;;        (redefine (head args) body ...+)

;; The form
;;     (redefine id expr)
;; expands to
;;     (define id expr)
;; or  (set!   id expr).

;; The very first time `id` is used in a redefinition, the
;; expansion will use `define`. Subsequently, it will use `set!`.


(require (for-syntax syntax/parse
                     syntax/parse/lib/function-header))

(begin-for-syntax
  (define redefinables '())
  (define (register-redefinable id) (set! redefinables (cons id redefinables)))
  (define (is-redefinable? id)      (member id redefinables free-identifier=?)))

(define-syntax (redefine stx)
  (syntax-parse stx
    ;; (redefine (head args) body ...+)
    [(_redefine header:function-header body ...+)
     (cond
       [(is-redefinable? #'header.name)
        (syntax/loc stx
          (set! header.name
                (let ()
                  (define header body ...)
                  header.name)))]
       [else
        (register-redefinable #'header.name)
        (syntax/loc stx
          (define header body ...))])]
    ;; (redefine id expr)
    [(_redefine id:id e:expr)
     (cond
       [(is-redefinable? #'id)
        (syntax/loc stx
          (set! id e))]
       [else
        (register-redefinable #'id)
        (syntax/loc stx
          (define id e))])]))


(redefine (foo x) (+ x 1))
(foo 10)
(define (bar x) (+ 10 (foo x)))
(bar 10)
(redefine (foo x) (+ x 2))
(foo 10)
(bar 10)
(redefine (foo x) (+ x 3))
(foo 10)
(bar 10)

(redefine baz 42)
baz
(redefine baz 43)
baz


(redefine hello 10)
(let ()
  (redefine (hello) "Hello")
  (displayln (hello))
  (redefine (hello) "Hi")
  (displayln (hello)))
hello ; => #<function>
   

(redefine (f x) 1)
(define ((g f) y) (f y))
(define h (g f))
(h 42) ; => 1 
(redefine (f x) 2)
(h 42) ; => 1
Clone this wiki locally