这会略微链接到我之前的两个问题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。
答案 0 :(得分:1)
我建议让diff
函数更多地处理 exp 。而不是一个大的lambda函数,为每个条件分支返回一个闭包,处理包括在lambda函数之外完成对diff
的递归调用。
在diff
中执行更多处理可能会在您前进时提高运行时性能,尤其是在重用调用diff
的结果时。它还可以使调试受益,因为在调用diff
时,而不是稍后在调用diff-eval
时,将捕获包括 exp 中的错误在内的许多错误。
答案 1 :(得分:0)
您可以使用现有的免费软件Computer Algebra System Maxima。 加载到您的Lisp图像中相对容易,您可以使用它 比衍生品更精细的任务。
从这里下载Maxima: git clone git://maxima.git.sourceforge.net/gitroot/maxima/maxima
在Emacs / SLIME中打开一个新的lisp文件并运行:
(require :asdf)
(setf asdf:*central-registry* (union '("/data/src/maxima/src/")
asdf:*central-registry*))
(require :maxima)
(in-package :maxima)
;; Documentation of how to convert between Lisp and Maxima:
;; http://maxima.sourceforge.net/docs/manual/en/maxima_3.html
;; this sets the Maxima variable foo to contain a list x, y:
(msetq $foo #$[x, y]$)
;; The lisp function displa displays a maxima expression:
(displa '((MLIST SIMP) $X $Y $Z))
;; and this stores the derivation of log(z) into foo:
(msetq $foo #$diff (log (z))$)
;; => ((MTIMES SIMP) ((MEXPT SIMP) $Z -1) ((%DEL SIMP) $Z))