Solution in Racket
What you try to do is actually to inject the pre-defined function body list construct into the body of a function definition (macro) call.
(define expr '(+ (* p p) (* x x)))
(eval `(define (fun x p) ,expr))
If you leave away the (eval ...)
layer, you see:
`(define (fun x p) ,expr)
;; '(define (fun x p) (+ (* p p) (* x x)))
The code, which is actually evaluated by the eval
.
Since this eval
takes place in the global environment level, no side effects are to be feared.
Below are my more complicated solutions with a define-expr
macro.
They explain, why it was so difficult to solve.
After all that, I saw that one needs actually only an (eval `(define (<args>) ,expr)
construct and actually no additional macro.
Complicated Solution in Racket
You can do it in Racket, too:
(define expr '(+ (* p p) (* x x)))
(define-syntax-rule (define-expr args expr)
(define args expr))
(eval `(define-expr (fun x p) ,expr))
This call executes in the background:
(define (fun x p) (+ (* p p) (* x x)))
What you try to do is actually a dynamic macro.
The problem with this is that you have to give the
function body code in runtime.
Somehow you need to evaluate the function body expression by one evaluation more than the rest of the macro.
Thus, it is necessary to wrap the macro call by an
(eval `<macrocall ,component-to-be-evaluated-once-more>)
I call this construct eval-over-macro-call
.
After this you can call the so-defined fun
function:
(fun 3 4) ;; 25
In common lisp
Personally, I prefer common lisp's macro system. it is more direct.
(defparameter *expr* '(+ (* p p) (* x x)))
(defmacro defun-expr (fnname args expr)
`(defun ,fnname ,args ,expr))
(macroexpand-1 '(defun-expr fun (x p) *expr*)) ;; doesn't work
;; (DEFUN FUN (X P) *EXPR*) ;
;; T
;; you can see, that *EXPR* actually has to be evaluated once more
(macroexpand-1 `(defun-expr fun (x p) ,*expr*)) ;; this however is correct
;; (DEFUN FUN (X P) (+ (* P P) (* X X)))
;; Thus when you call the macro, you have to execute it using eval:
(eval `(defun-expr fun (x p) ,*expr*))
;; FUN ;; function is defined!
(fun 3 4) ;; 25
Since I am not that familiar with Racket's macro system, I did the macro construction in common lisp using the great macroexpand-1
which shows the code construct executed by the macro. And then transferred/guessed the corresponding define-syntax-rule
in Racket.
In Racket, macroexpand-1
is (syntax->datum (expand-once '<macrocall>))
:
(syntax->datum (expand-once `(define-expr (fun x p) ,expr)))
;; '(define (fun x p) (+ (* p p) (* x x)))