determining which functions are defined programmatically

Viewed 59

I'd like to replace calls to specific set of functions to my implementations if available, for instance:

(define (call-my-fn f . args)
  (cond [(eq? f append) (apply my-append args)]))

All of my implementations are in a separate file and I don't want to keep adding to the cond clause. Is there a way I can write something like:

(require "my-fns.rkt")
(define (call-my-fn f . args)
  (cond [(is-defined? f "my-fns.rkt") (apply "my-version-of-f" args)]))
1 Answers

dynamic-require can be used to query a provided variable in other modules dynamically. The third argument of dynamic-require controls what should happen when the queried variable doesn't exist, so you can do something like:

;; lib.rkt

#lang racket

(provide foo bar)
(define foo #f)
(define (bar x) x)
;; client.rkt

#lang racket

(define does-not-exist (gensym))
(eq? (dynamic-require "lib.rkt" 'foo (λ () does-not-exist)) does-not-exist) ; #t
(eq? (dynamic-require "lib.rkt" 'bar (λ () does-not-exist)) does-not-exist) ; #t
(eq? (dynamic-require "lib.rkt" 'baz (λ () does-not-exist)) does-not-exist) ; #f

One might try to simplify the above to

;; client.rkt

#lang racket

(dynamic-require "lib.rkt" 'foo (λ () #f)) ; #f
(dynamic-require "lib.rkt" 'bar (λ () #f)) ; #<procedure:bar>
(dynamic-require "lib.rkt" 'baz (λ () #f)) ; #f

This would work if you know that all provided identifiers are not bound to #f. But if that's not the case, it would give an incorrect result as shown above. The solution workarounds the problem by returning a fresh unique symbol does-not-exist which is only eq? to itself. Then, we can use eq? to test if the returned value is does-not-exist. If it is, then we know for sure that the identifier is not provided.

Related