这将略微链接到我之前的两个问题 link 1 , link 2 .我正在研究一些符号评估器,这将成为我的电路仿真项目的一部分。正如之前有人提到的,我已将注意力转向 lambda 函数和自动函数生成。
任务很简单。让我们用一些键和值定义哈希表。
(defparameter *my-hash* (make-hash-table :test #'equal))
(defun get-symbol-var (x)
(gethash x *my-hash*))
(defun symbol-var (x)
(gethash (rest x) *my-hash*))
这里是主要的推导函数。推导由带有一些递归的 lambda 函数生成过程执行。它只是一个示例,因此它可以执行变量、数字和两个输入的乘积的推导。
(defun diff (exp var)
#'(lambda (x) (cond
((numberp exp) 0)
((variablep exp)
(if (same-variablep exp var) 1 0))
((productp exp)
(+ (* (funcall (diff (second exp) var) x) ( eval-exp (third exp)))
(* (funcall (diff (third exp ) var) x) ( eval-exp (second exp))))))))
(defun diff-eval (equation var)
(funcall (diff equation var) (symbol-var var)))
一些有用的条件定义
(defun productp (x)
(eql (car x) '*))
(defun variablep (x)
(eql (car x) 'symbol-var))
(defun same-variablep (v1 v2)
(and (variablep v1) (variablep v2) (equal v1 v2)))
因为有些变量可以跳出推导循环,所以我定义了专门的求值函数。
(defun eval-exp (exp)
(cond
((numberp exp) exp)
((variablep exp) (get-symbol-var (rest exp)))
((sump exp) (+ (eval-var-symbol (third exp))
(eval-var-symbol (second exp))))
((productp exp) (* (eval-var-symbol (third exp))
(eval-var-symbol (second exp))))))
给数据库引入一些变量
(setf (gethash '(v 1) *my-hash* ) 1)
(setf (gethash '(v 2) *my-hash* ) 23)
(setf (gethash '(v 3) *my-hash* ) 1)
检验方程d(v1*v2)/dv1
(setf *equation* '(* (symbol-var v 2) (symbol-var v 1)))
(diff-eval *equation* '(symbol-var v 1))
我的做法是否正确?这能不能做的更清楚 LISP。
最佳答案
我建议让 diff
函数对 exp 进行更多处理。不要使用一个大的 lambda 函数,而是为每个条件分支返回一个闭包,其中大部分处理包括在 lambda 函数之外完成的对 diff
的递归调用。
在 diff
中做更多的处理可能会随着您的前进提高运行时性能,特别是如果调用 diff
的结果被重用。它还有助于调试,因为包括 exp 在内的许多错误将在调用 diff
时被捕获,而不是稍后在调用 diff-eval
时被捕获。
关于lisp - 我对符号求值器对动态变量集进行推导的想法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5652486/