Write extensions to the Arc compiler in Arc

--- a/ac.scm	2009-11-21 10:39:51.000000000 -0500
+++ b/ac.scm	2009-11-21 10:38:31.000000000 -0500
@@ -9,6 +9,23 @@
 (require (lib ""))
+(define (ac-global-name s)
+  (string->symbol (string-append "_" (symbol->string s))))
+(define-syntax defarc
+  (syntax-rules ()
+    ((defarc (name . args) body ...)
+     (defarc name (name . args) body ...))
+    ((defarc arc-name (scheme-name . args) body ...)
+     (begin
+       (xdef arc-name (lambda args body ...))
+       (defarc arc-name scheme-name)))
+    ((defarc arc-name scheme-name)
+     (define (scheme-name . args)
+       (apply (namespace-variable-value (ac-global-name 'arc-name)) args)))
+    ((defarc name)
+     (defarc name name))))
 ; compile an Arc expression into a Scheme expression,
 ; both represented as s-expressions.
 ; env is a list of lexically bound variables, which we
@@ -209,9 +226,6 @@
-(define (ac-global-name s)
-  (string->symbol (string-append "_" (symbol->string s))))
 (define (ac-var-ref s env)
   (if (lex? s env)

Some extensions to the Arc compiler are more fun to write in Arc than in Scheme, so this patch allows a Scheme function in ac.scm to be implemented with Arc code.

Inside of ac.scm:

(defarc foo)

Defines in Scheme a function foo, that when called, calls the Arc function foo. Note that there’s no automatic translation between Scheme and Arc values in the function arguments or return value, so you may need to call ac-denil or ac-niltree etc. on one side or the other.

(defarc foo bar)

Defines in Scheme a function bar, that when called, calls the Arc function foo. (This is useful if you want to call a function in Arc when there's already a Scheme function with the same name).

(defarc (foo . args) body...)

Defines in Scheme a function foo that calls foo in Arc, and also provides (like xdef) an initial definition of the Arc function in Scheme, that can be later redefined or extended in Arc.

This syntax matches that of Scheme’s define, so that you can replace a define with a defarc to allow that Scheme function to be hacked in Arc.

For example, in arc3 ac.scm, the definition of literal? reads:

(define (literal? x)
  (or (boolean? x)
      (char? x)
      (string? x)
      (number? x)
      (eq? x '())))

Change the “define” to a “defarc”:

(defarc (literal? x)
  (or (boolean? x)
      (char? x)
      (string? x)
      (number? x)
      (eq? x '())))

And in Arc:

arc> literal?
arc> (literal? 3)
arc> (literal? '(a b c))

(note how we’re getting Scheme true and false values here).

This is different than

(xdef literal? literal?)

because calls in the Arc compiler to the Scheme version of literal? are actually calling the Arc literal? version. Thus changes to literal? in Arc will change how the Arc compiler operates. For example, suppose we wanted a byte string to be treated by Arc as a literal value (which it currently isn't):

arc> #"hello"
Bad object in expression #"hello"

We can extend Arc to do that by changing the definition of literal? in Arc:

arc> (extend literal? (x) (scheme.bytes? x)
#<procedure: literal?>
arc> #"hello"

(scheme from scheme0 lets us call Scheme code from Arc, and extend0 provides a convenient way of extending an Arc function).

(defarc foo (bar . args) body...)

Defines in Scheme a function bar that calls the Arc function foo, providing an initial definition in Scheme for the Arc function.

This is useful when we want to have the function to have a different name in Arc than in the Scheme. For example, we might prefer to have literal? be called ac-literal in Arc:

(defarc ac-literal (literal? x)
  (or (boolean? x)
      (char? x)
      (string? x)
      (number? x)
      (eq? x '())))
arc> (extend ac-literal (x) (scheme.bytes? x)
#<procedure: ac-literal>
arc> #"hello"

See also

rntz’s port of the Arc compiler to Arc.

Get this hack

Download defarc0.patch.

Or, using the hackinator:

hack \


This code may be redistributed and modified under the same terms as Arc itself.

Contact me

Twitter: awwx
Email: andrew.wilcox [at]