【问题标题】:lisp simplify polynomialslisp 简化多项式
【发布时间】:2012-12-01 01:08:44
【问题描述】:

我正在编写一个简化多项式的程序,现在只做加法和乘法。

我已经用头敲击键盘几个小时了,我想是时候寻求帮助了。

(defun simplify (lis)
    (if (eq (car lis) '+)
        (cons '+ (simplify-addition (cdr lis)))
        (if (eq (car lis) '*)
            (cons '* (simplify-multiplication (cdr lis))) 
        )
    )
)
(defun simplify-addition (lis)
    (if (not (null lis))
        (if (listp (car lis))
            (list (simplify (car lis)) (simplify-addition (cdr lis)))
            (if (numberp (car lis))
                (if (eq (car lis) 0)
                    (simplify-addition (cdr lis))
                    (if (null (cdr lis))
                        lis
                        (cons (car lis) (simplify-addition (cdr lis)))
                    )
                )
                (if (eq (car lis) '+)
                    (list (car lis) (simplify-addition (cdr lis)))
                    (if (eq (car lis) '*)
                        (list (car lis) (simplify-addition (cdr lis)))
                        lis
                    )
                )
            )
        )
    )
)

(defun simplify-multiplication (lis)
    (if (not (null lis))
        (if (listp (car lis))
            (if (find 0 (car lis))
                0
                (list (simplify (car lis)) (simplify-multiplication (cdr lis)))
            )
            (if (numberp (car lis))
                (if (null (cdr lis))
                    lis
                    (cons (car lis) (simplify-multiplication (cdr lis)))
                )
                (if (eq (car lis) '+)
                    (list (car lis) (simplify-multiplication (cdr lis)))
                    (if (eq (car lis) '*)
                        (list (car lis) (simplify-multiplication (cdr lis)))
                        lis
                    )
                )
            )
        )
    )
)

这是应该发生的:

(simplify ‘(+  x  ( + 0 3 )  ( * 1 5 )  ( * ( * x  y  z ) 0 )  ))  -->  ( + x 3 5 )
(simplify ‘(* (+ 6  0)  (* 1 6 2)))  -------------------------------->  (* 6 (* 6 2))

但是我要么得到与我发送的相同的多项式,要么完全关闭

编辑: 我需要的简化是从添加中删除 0,以便:

(+ 3 0)   --> 3
(+ 4 0 6) --> (+ 4 6)

与零的乘法被删除

(* 6 0 7) --> 0 

【问题讨论】:

  • +1 表示您的缩进样式,-1 表示不说明您会得到什么结果
  • 所以你应该只简化一个级别?我问是因为在您的第二个示例中,结果可以简化为 72,但您只能走到 (* 6 (* 6 2))
  • 我更新了这个问题,更具体地说明了函数应该做什么。
  • 请学习如何format Lisp code properly

标签: lisp polynomial-math


【解决方案1】:

首先,您可能想稍微改进一下编码风格以使其可读。

  • 不要将括号放在自己的行上。这只是浪费空间,根本没有帮助。

  • 不要在域特定代码中使用 CAR 和 CDR。领域是数学。您使用表达式(operator arg1 arg2)。而是使用CARCDR 定义函数OPERATORARGUMENTS 并使用它们。

  • 使用CASECOND 和其他多路条件表达式,而不是嵌套的IF - 有用的地方。

  • 尝试从域代码中提取数据结构的遍历。使用高阶函数而不是递归(MAPREDUCE、...)。

例子:

一些基本的领域功能:

(defun operator (expression)
  (first expression))

(defun arguments (expression)
  (rest expression))

(defun make-expression (operator arguments)
  (if (= (length arguments) 1)
      (first arguments)
    (cons operator arguments)))

(defun is-zero? (expression)
  (and (numberp expression)
       (= expression 0)))

现在简化:

(defun simplify (expression)
  (if (atom expression)
      expression
    (case (operator expression)
      (+ (make-expression '+ (simplify-addition       (arguments expression))))
      (* (make-expression '* (simplify-multiplication (arguments expression)))))))

(defun simplify-addition (expressions)
  (remove-if #'is-zero?
             (mapcar #'simplify
                     (remove-if #'is-zero? expressions))))

(defun simplify-multiplication (expressions)
  (if (member-if #'is-zero? expressions)
      (list 0)
    (let ((expressions1 (mapcar #'simplify expressions)))
      (if (member-if #'is-zero? expressions1)
          (list 0)
        expressions1))))

看看,代码的可读性提高了多少?不再有CARLISCDR。递归调用的意图也更容易理解。

它仍然不是最佳的,但它应该能让你继续前进。

【讨论】:

    【解决方案2】:

    我只看过simplify-multiplication,但这里有很多问题。

    一般来说,您希望先递归简化,然后再检查特定常量。 (我猜是后序遍历。)

    其次,我没有看到你在任何地方检查 1,所以我看不到 (* 1 5) ==> 5 应该如何工作。

    第三,让我们来看看(simplify '(* (+ 2 0) 3))

    (defun simplify-multiplication (lis)
    ; lis = '((+ 2 0) 3)
        (if (not (null lis))
        ; ==> t
            (if (listp (car lis))
            ; (car lis) = '(+ 2 0), so (listp '(+ 2 0)) ==> t
                (if (find 0 (car lis))
                ; succeeds because '(+ 2 0) contains 0
                ; this is completely wrong! you're not supposed to check sublists of lis
                    0
                    ; ... yeah, you just returned 0 just because there was a 0 *somewhere*
                    (list (simplify (car lis)) (simplify-multiplication (cdr lis)))
                )
                ...
    

    (simplify '(* 0 2)):

    (defun simplify-multiplication (lis)
    ; lis = '(0 2)
        (if (not (null lis))
        ; ==> t
            (if (listp (car lis))
            ; (car lis) = 0, so (listp 0) ==> nil
                (if (find 0 (car lis))
                    0
                    (list (simplify (car lis)) (simplify-multiplication (cdr lis)))
                )
                (if (numberp (car lis))
                ; (numberp 0) ==> t
                    (if (null (cdr lis))
                    ; (cdr lis) = '(2), so (null '(2)) ==> nil
                        lis
                        (cons (car lis) (simplify-multiplication (cdr lis)))
                        ; ... wait, what?
                        ; you're just recursively walking through the list without
                        ; checking what numbers you actually got. this won't simplify
                        ; anything.
                    )
                    (if (eq (car lis) '+)
                    ; what is this branch for? it can only succeed if you have code of the form
                    ;   (* 1 + 2)
                    ; which is a syntax error
                        (list (car lis) (simplify-multiplication (cdr lis)))
                        (if (eq (car lis) '*)
                        ; this branch is for code like (* * *). huh???
                            (list (car lis) (simplify-multiplication (cdr lis)))
                            lis
                        )
                    )
                )
            )
        )
    )
    

    【讨论】:

    • 如果你已经阅读了整个内容,你会看到当它遇到一个列表元素时,它会将它发送回读取第一个字符(+ 或 )的简化函数然后将其发送到相应的函数,因此在您的第一个示例中,一旦它获得第一个元素(列表),它就会看到这是一个加法并将其发送到那里。同样在乘法函数中,如果该列表上的任何地方都有零,我确实想返回 0,因为 ( 0 x) --> 0
    • 如果您阅读过我的 cmets,您会发现在我的示例中它不会返回到 simplify。我同意如果参数中有 0,您确实希望返回 0,但代码没有这样做。相反,它返回 0 如果其中一个参数是另一个列表并且该内部列表包含 0
    • 对不起,如果我的评论听起来很粗鲁,而不是我的本意,您的评论非常有帮助,让我发现了我的一些错误。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-27
    • 1970-01-01
    • 2013-12-03
    • 1970-01-01
    • 2010-10-07
    相关资源
    最近更新 更多