1

这将略微链接到我之前的两个问题 链接 1链接 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。

4

2 回答 2

1

我建议让函数对expdiff进行更多处理。代替一个大的 lambda 函数,为每个条件分支返回一个闭包,其中大部分处理包括diff在 lambda 函数之外完成的递归调用。

diff在您前进时,执行更多处理可能会提高运行时性能,尤其diff是在重用调用结果的情况下。它也有利于调试,因为包括expdiff在内的许多错误将在调用时而不是稍后在调用时被捕获diff-eval

于 2011-04-14T19:27:19.050 回答
0

您可以使用现有的免费软件 Computer Algebra System Maxima。加载到您的 Lisp 映像中相对容易,您可以将其用于更复杂的任务,而不仅仅是衍生产品。

从这里下载千里马: 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))
于 2011-07-02T13:17:59.310 回答