如何用函数生成的符号表达式定义数值计算函数(Chez Scheme)
Chez Scheme 符号微分实现:从符号表达式到可执行数值函数
已完成的基础符号微分功能
我在Chez Scheme中实现了一个符号微分函数,目前完成了基础功能(暂未实现表达式化简):
(define (derive var expr) ;; var 是求导的自变量 (if (list? expr) (case (car expr) ('+ (sum-rule var expr)) ('- (sub-rule var expr)) ('* (prod-rule var expr)) ;; 其他规则待补充 (else (atomic-rule var expr ))) (atomic-rule var expr))) (define (atomic-rule var expr) (if (list? expr) expr (if (eqv? var expr) 1 0))) (define (sum-rule var expr) (let ((args (cdr expr))) `(+ ,@(map (lambda (e) (derive var e)) args)))) (define (sub-rule var expr) (let ((args (cdr expr))) `(- ,@(map (lambda (e) (derive var e)) args)))) (define (prod-rule var expr) (let* ((args (cdr expr)) (f (car args)) (g (cadr args))) `(+ (* ,f ,(derive var g)) (* ,g ,(derive var f)))))
执行(derive 'x '(+ (* x x) (* x y)))可以得到正确的符号表达式:(+ (+ (* x 1) (* x 1)) (+ (* x 0) (* y 1)))。但我需要程序化地将这类符号表达式转换为能直接返回数值结果的函数。
失败的尝试
我做了两次尝试都没成功:
(define (lambda-derive var expr) (let ([derivative (derive var expr)]) (lambda (var) derivative))) ((lambda-derive 'x '(* x x)) 2) => (+ (* x 1) (* x 1)) ;; 期望结果是4 (define-syntax lbd-macro (lambda (context) (syntax-case context () [(k expr var ) (with-syntax ([new-var (datum->syntax #'k (syntax->datum #'var))]) #'(lambda (new-var) expr))])) ((lbd-macro (derive 'x '(* x x)) x) 2) => (+ (* x 1) (* x 1)) ;; 期望结果是4
我感觉自己漏掉了某个关键点,希望能得到指点(注:当前尝试未考虑多变量场景)。
调试后的解决方案
经过连夜调试,我得到了一个可行的方案(使用哈希表,实现方式偏粗糙),和@ignis volens描述的思路类似:
(define (lambda-aux variables vals expr) (let ((ht (make-eqv-hashtable (length variables)))) (for-each (lambda (k v) (hashtable-set! ht k v)) variables vals) (let loop ((expr expr)) (if (list? expr) (let ((op (car expr)) (args (map loop (cdr expr)))) (cons op args)) (let ((variable (hashtable-ref ht expr #f))) (if variable variable (if (number? expr) expr (error "variable not found")))))))) (define-syntax lambda-derive (syntax-rules () [(_ expr var var* ...) (lambda (var var* ...) (eval (lambda-aux '(var var* ...) (list var var* ...) (derive 'var 'expr) )))]))
使用示例
(define my-test-derivative ;; f(x,y) = x² + x*y ;; df/dx (x,y) = 2x + y (lambda-derive (+ (* x y) (* x x)) x y)) (my-test-derivative 2 2) => 6 (my-test-derivative 8 2) => 18 ;; ...
内容的提问来源于stack exchange,提问作者nemo nemo
相关产品推荐
相关产品推荐

