我是一名Lisp noobie,在理解loop
和format
合并后的工作方式时遇到一些困难。
这符合我的预期:
(loop for i upto 2 do (format t "~a" "Badger")) ==>
BadgerBadgerBadger
NIL
这不是:
(loop for i upto 2 do (format nil "~a" "Badger")) ==>
NIL
为什么第二个循环不返回BadgerBadgerBadger
?我必须编写什么代码来提供此返回值?
答案 0 :(得分:3)
返回值和打印值之间存在重要区别。有时这在REPL中会引起混淆,因为默认情况下会打印返回值:
CL-USER> (+ 1 1) ; form *returns* 2
2 ; and return value (2) is printed
CL-USER> (let ()
(+ 1 1) ; (+ 1 1) still returns 2, but
nil) ; the return value of the (let ...) is NIL
NIL ; so NIL is printed
现在,格式可以做一些不同的事情,具体取决于它的第一个参数。如果它的第一个参数是 t ,或者是一个流,那么它会将输出写入流并返回nil:
CL-USER> (format t "hello")
hello ; printed output
NIL ; return value from format
CL-USER> (let ()
(format t "hello") ; will print "hello"
42) ; but the whole form returns 42
hello ; printed output
42 ; printed return value
当使用 nil 作为第一个参数调用format时,它会返回它作为字符串生成的输出:
CL-USER> (format nil "hello")
"hello" ; return value, not printed output
CL-USER> (let ()
(format nil "hello") ; returns "hello"
42) ; but the whole form returns 42
42 ; printed return value
现在,您可以收集循环结果,听起来您想使用格式生成字符串,然后收集这些字符串:
CL-USER> (loop for i upto 2 collect i)
(0 1 2)
CL-USER> (loop for i upto 2 collect (* 8 i))
(0 8 16)
CL-USER> (loop for i upto 2 collect (format nil "string number ~a" i))
("string number 0" "string number 1" "string number 2")
答案 1 :(得分:2)
这取决于format
函数的第一个参数,称为 destination (参见manual):
如果 destination 是字符串,流或
的字符串t
,则结果为nil。否则,结果是包含'output'
在第一种情况下,format
写入标准输出(您看到三个" Budger")并返回NIL
。但是,您没有看到那个值,而是loop
返回的值NIL
。事实上,LOOP
中没有任何条款(如RETURN
)可以返回与NIL
不同的内容。
在第二种情况下,format
返回字符串,但循环的值再次为NIL
,这是整个表单的结果。
如果要返回格式的结果,可以编写:
(with-output-to-string (s)
(loop for i upto 2 do (format s "~a" "Badger")))
通过这种方式,format
功能"写"字符串流s
,由with-output-to-string
返回。