我在常见的lisp中看到了两种不同的“输出”功能模式:
(defun implicit ()
(format t "Life? Don't talk to me about life!"))
(defun explicit (stream)
(format stream "This will all end in tears."))
(defun test-im-vs-ex-plicit ()
(values
(with-output-to-string (stream)
(let ((*standard-output* stream))
(implicit)))
(with-output-to-string (stream)
(explicit stream))))
使用动态范围是像在implicit
不良实践中那样,还是动态范围界定被普遍接受?请注意,我假设这是用于例如DSL构建复杂的输出,例如HTML,SVG,Latex或其他任何东西,并且除了产生打印的表示形式之外,不会做任何其他事情。
除了样式外,是否还有其他重要差异,例如在性能,并发性等方面?
实际上,您可以*standard-output*
直接绑定:
(defun test-im-vs-ex-plicit ()
(values
(with-output-to-string (*standard-output*) ; here
(implicit))
(with-output-to-string (stream)
(explicit stream))))
没有真正简单的答案。我的建议:
使用流变量,这使调试更加容易。它们出现在参数列表中,并且更容易在回溯中发现。否则,您将需要在回溯中查看流变量的动态重新绑定。
a)没有通过?
(defun print-me (&optional (stream *standard-output*))
...)
b)一个或多个固定参数:
(defun print-me-and-you (me you &optional (stream *standard-output*))
...)
c)一个或多个固定参数和多个可选参数:
(defun print-me (me
&key
(style *standard-style*)
(font *standard-font*)
(stream *standard-output*))
...)
另请注意:
现在假设(implicit)
有一个错误,我们得到一个break循环,一个调试repl。在此中断循环中,标准输出的值是多少?
CL-USER 4 > (defun test ()
(flet ((implicit ()
(write-line "foo")
(cerror "go on" "just a break")
(write-line "bar")))
(with-output-to-string (stream)
(let ((*standard-output* stream))
(implicit)))))
TEST
CL-USER 5 > (compile 'test)
TEST
NIL
NIL
CL-USER 6 > (test)
Error: just a break
1 (continue) go on
2 (abort) Return to level 0.
3 Return to top loop level 0.
Type :b for backtrace or :c <option number> to proceed.
Type :bug-form "<subject>" for a bug report template or :? for other options.
CL-USER 7 : 1 > *standard-output*
#<SYSTEM::STRING-OUTPUT-STREAM 40E06AD80B>
CL-USER 8 : 1 > (write-line "baz")
"baz"
CL-USER 9 : 1 > :c 1
"foo
baz
bar
"
上面是您在LispWorks或SBCL中看到的内容。在这里,您可以访问真实程序的绑定,但是在调试过程中使用输出函数将对此流产生影响。
在其他实现中,*standard-output*
将反弹到实际终端io-例如在Clozure CL和CLISP中。
如果您的程序没有重新绑定*standard-output*
,那么在这些情况下,混乱就更少了。如果我编写代码,我经常会想到在REPL环境中更有用的方法-与语言不同,后者在REPL和中断循环上的交互调试较少...
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句