我将稀疏多项式表示为(系数,对)的列表.例如:
'((1 2) (3 6) (-20 48)) => x^2 + 3x^6 - 20x^48
Run Code Online (Sandbox Code Playgroud)
我是Lisp格式的新手,但是遇到了一些非常漂亮的工具,例如(format nil "~:[+~;-~]" (> 0 coefficient))
将系数的符号作为文本(我知道,这可能不是惯用的).
但是,格式化单个术语时存在某些显示问题.例如,以下内容应该都是真的:
(1 0) => 1x^0 => 1 (reducible)
(1 1) => 1x^1 => x (reducible)
(1 2) => 1x^2 => x^2 (reducible)
(2 0) => 2x^0 => 2 (reducible)
(2 1) => 2x^1 => 2x (reducable)
(2 2) => 2x^2 => 2x^2 (this one is okay)
Run Code Online (Sandbox Code Playgroud)
我想知道是否有一种方法可以在没有大量系列if
或cond
宏的情况下做到这一点 - 这种方式只需用一个format
模式来实现.一切都有效但是"美化"这些术语(最后一行FormatPolynomialHelper3
应该这样做).
(defun FormatPolynomial (p)
"Readably formats the polynomial p."
; The result of FormatPolynomialHelper1 is a list of the form (sign formatted),
; where 'sign' is the sign of the first term and 'formatted' is the rest of the
; formatted polynomial. We make this a special case so that we can print a sign
; attached to the first term if it is negative, and leave it out otherwise. So,
; we format the first term to be either '-7x^20' or '7x^20', rather than having
; the minus or plus sign separated by a space.
(destructuring-bind (sign formatted-poly) (FormatPolynomialHelper1 p)
(cond
((string= formatted-poly "") (format nil "0"))
(t (format nil "~:[~;-~]~a" (string= sign "-") formatted-poly)))))
; Helpers
(defun FormatPolynomialHelper1 (p)
(reduce #'FormatPolynomialHelper2 (mapcar #'FormatPolynomialHelper3 p) :initial-value '("" "")))
(defun FormatPolynomialHelper2 (t1 t2)
; Reduces ((sign-a term-a) (sign-b term-b)) => (sign-b "term-b sign-a term-a"). As
; noted, this accumulates the formatted term in the variable t2, beginning with an
; initial value of "", and stores the sign of the leading term in the variable t1.
; The sign of the leading term is placed directly before the accumulated formatted
; term, ensuring that the signs are placed correctly before their coefficient. The
; sign of the the leading term of the polynomial (the last term that is processed)
; is available to the caller for special-case formatting.
(list
(first t2)
(format nil "~@{~a ~}" (second t2) (first t1) (second t1))))
(defun FormatPolynomialHelper3 (tm)
; Properly formats a term in the form "ax^b", excluding parts of the form if they
; evaluate to one. For example, 1x^3 => x^3, 2x^1 => 2x, and 3x^0 => 3). The list
; is in the form (sign formatted), denoting the sign of the term, and the form of
; the term state above (the coefficient have forced absolute value).
(list
(format nil "~:[+~;-~]" (> 0 (first tm)))
(format nil "~a~@[x^~a~]" (abs (first tm)) (second tm))))
Run Code Online (Sandbox Code Playgroud)
编辑:正确地说,输出不应包含逻辑.也许我对问题的要求过于具体.这是正确格式化多项式的逻辑 - 但我正在寻找更清晰,更可读和更具口味的东西(这只是我写作lisp的第三天).
(defun FormatPolynomialHelper3 (tm)
; Properly formats a term in the form "ax^b", excluding parts of the form if they
; evaluate to one. For example, 1x^3 => x^3, 2x^1 => 2x, and 3x^0 => 3). The list
; is in the form (sign formatted), denoting the sign of the term, and the form of
; the term state above (the coefficient have forced absolute value).
(list
(format nil "~:[+~;-~]" (> 0 (first tm)))
(cond
((= 0 (second tm)) (format nil "~a" (abs (first tm))))
((= 1 (abs (first tm))) (cond
((= 1 (second tm)) (format nil "x"))
(t (format nil "x^~a" (second tm)))))
((= 1 (second tm)) (format nil "~ax" (abs (first tm))))
(t (format nil "~ax^~a" (abs (first tm)) (second tm))))))
Run Code Online (Sandbox Code Playgroud)
答案:
我不会把这个逻辑放在FORMAT
陈述中.仅当您要加密代码或为自己创建更多维护工作时.好的Lisp代码是自我记录的.FORMAT
陈述永远不会自我记录.
在打印之前,我会首先简化多项式.例如,删除每个乘以零的项.
((0 10) (1 2)) -> ((1 2))
Run Code Online (Sandbox Code Playgroud)
然后,如果乘数为1,则可以在正常COND
或CASE
语句中进行测试.
另外,还要确保你永远不会使用CAR
,CDR
,FIRST
,SECOND
用自制的数据结构.多项式的组件应该主要通过隐藏大部分实现细节的自记录函数来访问.
我会写它没有FORMAT
:
示例代码:
(defun term-m (term)
(first term))
(defun term-e (term)
(second term))
(defun simplify-polynomial (p)
(remove-if #'zerop (sort p #'> :key #'term-e)
:key #'term-m))
(defun write-term (m e start-p stream)
; sign or operator
(cond ((and (minusp m) start-p)
(princ "-" stream))
((not start-p)
(princ (if (plusp m) " + " " - ") stream)))
; m
(cond ((not (= (abs m) 1))
(princ (abs m) stream)))
(princ "x" stream)
; e
(cond ((not (= 1 e))
(princ "^" stream)
(princ e stream))))
(defun write-polynomial (p &optional (stream *standard-output*))
(loop for (m e) in (simplify-polynomial p)
for start-p = t then nil
do (write-term m e start-p stream)))
Run Code Online (Sandbox Code Playgroud)
使用示例:
CL-USER 14 > (write-polynomial '((1 2) (3 6) (-20 48)))
-20x^48 + 3x^6 + x^2
Run Code Online (Sandbox Code Playgroud)