Cat’s hacks:

defvar

Provide your own implementation for a global variable

defvar0.patch

diff --git a/ac.scm b/ac.scm
index 3f1663b..65b95d7 100644
--- a/ac.scm
+++ b/ac.scm
@@ -188,10 +188,15 @@
 (define (ac-global-name s)
   (string->symbol (string-append "_" (symbol->string s))))
 
+(define _defined-var* (make-hash-table 'equal))
+
+(define (defined-var? s)
+  (not (ar-false? (hash-table-get _defined-var* s #f))))
+
 (define (ac-var-ref s env)
-  (if (lex? s env)
-      s
-      (ac-global-name s)))
+  (cond ((lex? s env)     s)
+        ((defined-var? s) (list (ac-global-name s)))
+        (#t               (ac-global-name s))))
 
 ; quasiquote
 
@@ -366,6 +371,7 @@
                (cond ((eqv? a 'nil) (err "Can't rebind nil"))
                      ((eqv? a 't) (err "Can't rebind t"))
                      ((lex? a env) `(set! ,a zz))
+                     ((defined-var? a) `(,(ac-global-name a) zz))
                      (#t `(namespace-set-variable-value! ',(ac-global-name a) 
                                                          zz)))
                'zz))

defvar0.arc

; Have to use ac-set-global here, as using = or assign would invoke
; our own previously defined settor when defvar was called on the same
; variable twice.

(mac defvar (name impl)
  `(do (ac-set-global ',name ,impl)
       (set (defined-var* ',name))
       nil))

(mac defvar-impl (name)
  (let gname (ac-global-name name)
    `(ac-scheme ,gname)))

(mac undefvar (name)
  `(do (wipe (defined-var* ',name))
       (wipe ,name)))
  
; idea: extend def and mac to call undefvar so that a defvar can be
; redefined as a function or a macro?
;
; Is there a reason why we need to store the defvar's implementation
; procedure in the global variable namespace?  A reason not to?

description

This hack provides for a way to provide your own implementation for a global variable, to say what happens when the variable is used or set:

 arc> (def foo ()
        (prn "This is foo, I'm going to return 5.")
        5)
 #<procedure: foo>
 arc> (defvar a foo)
 nil
 arc> (+ a 3)
 This is foo, I'm going to return 5.
 8

foo is now providing the implementation for the global variable a; when the variable is used in an expression, foo is called and the value of the variable is what is returned by foo.

If the variable is set, the implementing function is called with a single argument, the value the variable is being set to:

 arc> (def foo args
        (if args
             (prn "Being set to " (car args) ".")
             (do (prn "Returning 5.")
                 5)))
 #<procedure: foo>
 arc> (defvar a foo)
 nil
 arc> (++ a)
 Returning 5.
 Being set to 6.
 6

prerequisites

get this hack

wget http://ycombinator.com/arc/arc3.tar
tar xf arc3.tar
cd arc3
wget -O - http://hacks.catdancer.ws/ac0.patch | patch
wget -O - http://hacks.catdancer.ws/defvar0.patch | patch
wget http://hacks.catdancer.ws/ac0.arc
wget http://hacks.catdancer.ws/defvar0.arc
mzscheme -m -f as.scm
(load "ac0.arc")
(load "defvar0.arc")

comment

Comment in the Arc Forum.

license

public domain