A technique I stumbled on while implementing a bunch of crazy tricks in arc-on-mzscheme (just to return to the principle of true axiomatic development) is to create fake scheme-side objects that act as Arc functions (you do have to change the 'disp and 'write functions, and probably handle errors yourself, so that the user doesn't know you're faking functions). Something like this:
(define (composer fl fr)
(vector 'composer fl fr))
(define (composer? fn)
(and (vector? fn) (eq? 'composer (vector-ref fn 0))))
(define (composer-fl fn) (vector-ref fn 1))
(define (composer-fr fn) (vector-ref fn 2))
; 'compose is now a reduction on '<base>compose
(xdef '<base>compose composer)
; this is where the speedup comes from!
(define (ar-funcall0 fn)
(cond
((composer? fn)
(let ((fl (composer-fl fn))
(fr (composer-fr fn)))
(ar-funcall1 fl (ar-funcall0 fr))))
...))
;etc. for ar-funcall1 to 4 and ar-apply.