我正在尝试创建一个宏,它将接受输入流并根据读取的第一行的内容执行不同的操作,然后读取更多输入。我只是有一个宏来接收输入流并从中读取一些值。
一个人为的例子:
(defmacro read-and-print (&optional in)
`(print
,(if (string= (read-line in) "greet")
`(concatenate 'string "hello" (read-line ,in))
`(read-line ,in))))
(with-input-from-string (in "greet
bob") (read-and-print in))
但即使这样也会产生以下错误
There is no applicable method for the generic function
#<STANDARD-GENERIC-FUNCTION SB-GRAY:STREAM-READ-LINE (1)>
when called with arguments
(IN).
[Condition of type SB-INT:COMPILED-PROGRAM-ERROR]
令我感到困惑的是,甚至更改函数以获取第一行的字符串不起作用:
(defmacro read-and-print (command &optional in)
`(print
,(if (string= command "greet")
`(concatenate 'string "hello " (read-line ,in))
`(read-line ,in))))
(with-input-from-string (in "greet
bob")
(read-and-print (read-string in) in))
这给了我
The value
(READ-LINE IN)
is not of type
(OR (VECTOR CHARACTER) (VECTOR NIL) BASE-STRING SYMBOL CHARACTER)
when binding SB-IMPL::STRING1
[Condition of type SB-INT:COMPILED-PROGRAM-ERROR]
虽然这完全可以执行:
(with-input-from-string (in "greet
bob")
(read-and-print "greet" in))
我遗失的with-input-from-string
宏有什么特别之处吗?我怀疑我遗漏了一些关于宏的非常明显的东西,但谷歌搜索让我无处可去。
答案 0 :(得分:3)
宏是一种代码生成工具。 他们不评估他们的论点。
您的with-input-from-string
示例有效,因为字符串是自我评估的。如果您完全是字符串文字,则会出错。
你不需要一个宏。改为使用函数。
在决定功能和宏之间时,你需要问问自己:
除非您理解问题并回答是,否则您应该使用函数。
答案 1 :(得分:1)
你的宏:
(defmacro read-and-print (&optional in)
`(print
,(if (string= (read-line in) "greet")
`(concatenate 'string "hello" (read-line ,in))
`(read-line ,in))))
但是,(if ... in ...)
毫无意义,因为in
的值通常不是宏扩展时的流,而是代码(符号,表达式......)。由于您的代码没有执行,并且宏看到了源(而不是尚未执行的值的值),因此您无法执行此操作。你也无法有效地修复它:它只是错误的方法。改为使用函数。
使用功能:
CL-USER 17 > (defun read-and-print (&optional in)
(if (string= (read-line in) "greet")
(concatenate 'string "hello" (read-line in))
(read-line in)))
READ-AND-PRINT
CL-USER 18 > (with-input-from-string (in "greet
foo
bar")
(read-and-print in))
"hellofoo"
使用宏
您仍然可以将其编写为宏,但是您需要生成代码以便它在运行时运行,而不是在宏扩展时运行:
(defmacro read-and-print (&optional in)
`(print
(if (string= (read-line ,in) "greet")
(concatenate 'string "hello" (read-line ,in))
(read-line ,in))))
注意:人们实际上可能想要处理in
未多次评估。
这个宏会为您提供代码内联的优势。 这个宏会给你带来代码内联的缺点。
上面的函数为您提供了代码通常不内联的优势。 上面的函数通过告诉编译器使用内联声明来实现代码,可以选择内联代码。