我目前正在编写一个关于输入 P 的函数是正常形式的 PExpr。以以下"常识"格式输出表示 P 的字符串
这是我现在得到的:
(defun writepoly (a b start)
(cond
((and (minusp a) start)
(princ "-"))
((not start)
(princ (if (plusp a) " + " " - "))))
(cond
((not (equal (abs a) 1))
(princ (abs a))))
(cond
((equal (abs b) 1)
(princ "x"))
((> (abs b) 1)
(princ "x")
(princ "^")
(princ b))))
(defun print-pexpr (P)
(loop for (a . b) in P
for start = t then nil
do (write-to-string (writepoly a b start))
我确实得到了正确的结果,例如
(print-pexpr '((-1 . 10) (-23 . 0)))
-x^10 - 23
NIL
但是当我做测试用例时
(defun test-case (ID Test Result)
(if (equal Test Result)
(format nil "Test ~S OK" ID)
(format nil "FAIL: Test ~S expected ~S got ~S" ID Result Test)
)
)
(test-case 6.4
(print-pexpr '((-1 . 10) (-23 . 0)))
"-x^10 - 23"
)
输出为:
"FAIL: Test 6.4 expected "-x^10 - 23" got NIL
如何更改我的函数以便我可以获取字符串...? 我不应该使用 princ 命令吗?希望有人能回答我的问题...谢谢
PS:我在Lisp格式多项式中复制了该方法
像princ
、print
、ecc 这样的函数执行两个不同的任务:
- 他们将参数打印在标准输出上,通常是终端,但如果特殊变量
*standard-output*
被反弹,则可能会有所不同; - 它们返回打印为语言值的参数。
例如:
CL-USER> (+ (print 1) (print 2))
1 ; <- printed by (print 1), which returns also 1
2 ; <- printed by (print 2), which returns also 2
3 ; <- the sum of 1+2, printed by the REPL, not by the program!
因此,如果您尝试例如(writepoly -1 10 t)
,您将获得:
CL-USER> (writepoly -1 10 t)
-x^10 ; <- printed by writepoly
10 ; <- returned by writepoly
换句话说,您的程序打印某些内容并返回其他内容,例如最后一个函数,在该函数中,您打印多项式但返回 NIL(通过读取调用print-pexpr
后的两行很清楚),这就是错误的原因。
如何修改程序以返回打印的字符串?基本上有两种可能。第一个是 Rainer Joswing 的答案所建议的,使用两件事:函数with-output-to-string
,它创建一个新的输出流,其中"打印"的所有内容在末尾作为单个字符串返回,第二个通过给出该流的名称*standard-output*
,在实践中"指示"所有打印命令(没有显式流参数)在该字符串上打印(否则您应该更改所有打印通过显式添加要在其上打印的流来调用)。
因此,您可以使用以下命令更改最后一个函数:
(defun print-pexpr (P)
(with-output-to-string (*standard-output*)
(loop for (a . b) in P
for start = t then nil
do (writepoly a b start))))
另一种方法是,不是将结果打印到某个流,而是通过使用带有第一个参数NIL
的format
将其转换为字符串,而不是 print(例如(format () "~a" expression)
),然后在组合不同部分时将所有这些字符串concatenate
为一个字符串(再次使用format
或concatenate
)。这需要对程序进行更多更改。
CL-USER 6 > (with-output-to-string (*standard-output*)
(princ 'foobar))
"FOOBAR"