I am implementing a genetic programming application in which arithmetic expressions, containing
safe-sqrt, are dynamically generated by a function (as lists). To calculate the fitness of these expressions, I need to use
eval to turn them into executable functions. However, since Racket's
eval cannot see local bindings in the context where it is called, I did the following:
#lang racket (define (make-lambda args expression) (eval `(let ([safe-div (lambda (x y) (if (= y 0) 1 (/ x y)))] [safe-sqrt (lambda (x) (sqrt (abs x)))]) (lambda ,args ,expression)) (make-base-namespace))) (writeln ((make-lambda '(x y) '(+ x (safe-sqrt y))) 2 -9)) ; writes 5 (writeln ((make-lambda '(x y) '(+ x (safe-div y 0))) 2 -9)) ; writes 3
That works! However, I would like to know if there is a better alternative to solve this problem.
#lang racket/base (require racket/sandbox) ; Kebab-case, not snake_case! (define safe-evaluator (make-evaluator 'racket/base '(define (safe-div x y) (if (= y 0) 1 (/ x y))) '(define (safe-sqrt x) (sqrt (abs x))))) (safe-evaluator '((lambda (x y) (+ x (safe-sqrt y))) 2 -9)) (safe-evaluator '((lambda (x y) (+ x (safe-div y 0))) 2 -9))
You can also use sandboxes to add restrictions like how much time or memory should be used evaluating things and other fine tuning about its permissions and such if you're really worried about safety.
If there's a lot of functions, it might be better to organize things by putting them all in a module of their own and requiring it:
(module safe-functions racket/base (provide safe-div safe-sqrt) (define (safe-div x y) (if (= y 0) 1 (/ x y))) (define (safe-sqrt x) (sqrt (abs x)))) (define safe-evaluator (make-evaluator 'racket/base #:requires '((submod "eval.rkt" safe-functions))))
"eval.rkt" with the name of your source file, or if using a top level module instead, the whole
submod expression with its name just like you'd do for a normal