为啥 Lisp 中的单引号总是返回大写?
Posted
技术标签:
【中文标题】为啥 Lisp 中的单引号总是返回大写?【英文标题】:Why does single quote in Lisp always return upper case?为什么 Lisp 中的单引号总是返回大写? 【发布时间】:2015-08-11 13:49:23 【问题描述】:我希望能够从单引号中设置大小写,但这似乎不可能。
(format nil "The value is: ~a" 'foo)
"The value is: FOO"
(format nil "The value is: ~a" 'FOO)
"The value is: FOO"
(format nil "The value is: ~a" "Foo")
"The value is: Foo"
【问题讨论】:
【参考方案1】:引用
报价与大小写无关。 quote
阻止评估。
引用一个符号:
CL-USER 1 > 'foo
FOO
引用列表:
CL-USER 2 > '(1 2 3 foo)
(1 2 3 FOO)
你可以在很多东西前面加上引号。比如前面一个字符串:
CL-USER 3 > '"a b c"
"a b c"
由于字符串对自身进行评估,因此是否引用它们没有区别:
CL-USER 4 > "a b c"
"a b c"
符号默认为大写:
CL-USER 5 > 'FooBar
FOOBAR
CL-USER 6 > (symbol-name 'FooBar)
"FOOBAR"
但这与引用无关,是阅读器的一个功能。
CL-USER 7 > (read-from-string "foo")
FOO
3
小写
如果你想要小写的字符串,你需要将字符串转换为小写:
CL-USER 8 > (string-downcase (symbol-name 'FooBar))
"foobar"
混合大小写的符号
但是您可以创建具有小写名称或混合大小写的符号。你需要逃避它们:
CL-USER 9 > '|This is a symbol With spaces and mixed case|
|This is a symbol With spaces and mixed case|
CL-USER 10 > 'F\o\oB\a\r
|FooBar|
使用FORMAT
缩小输出
您也可以告诉FORMAT
以小写形式打印:
CL-USER 11 > (format nil "The value is: ~(~a~)" 'foo)
"The value is: foo"
【讨论】:
感谢您的回答!很有帮助。 所以代码使用'value是一个字符串是不好的?我想我在几个地方遇到了这种情况。 @Jiminion:你能解释一下你的问题是什么意思吗?我不确定我是否明白你在问什么。'int
是一个符号。它占用的空间更少,因为它是实习的,而字符串不一定如此。比较符号和比较指针一样快;而比较字符串在最坏的情况下涉及 O(n)。符号大多是内部的:在其他语言中使用幻数或常量的地方使用它们;通常,它们不应该被打印出来。有什么理由更喜欢字符串而不是符号?您希望获得什么?
最后一部分也适用于所有数据类型。在Practical Common Lisp :: A few format recipes 中,还有另外 3 个关于外壳固定的其他变体。 (在页面上搜索“狐狸”)【参考方案2】:
'foo
表示“禁止对符号 FOO 的评估,只留下符号 FOO”。 Common Lisp 默认情况下倾向于向上转换符号名称(因此表示为'foo
、'Foo
和'FOO
的符号都是同一个符号,符号名称为"FOO"
)。
要确切了解您的实现将做什么,您可以通过调用(readtabe-case *readtable*)
检查当前可读表see CLHS, ch 23.1.2, effect of readtable case 的可读情况。
一些 lisp 实现将以 :preserve
的 readtable-case 开头。
至于是否应该使用符号或字符串,这是“取决于”的其中之一。如果您不担心 cse 保存,使用 interned 符号可以减少存储空间并加快比较速度,并且以(可能的)大小写处理的代价。但是,如果大小写很重要,那么平衡可能会更接近“使用字符串”的范围。
【讨论】:
这听起来像是预优化,但 Stack Overflow 中的许多人似乎对此不以为然。 把它想象成语义胜于表现。符号是一个“值”,例如常量或enum
字段。字符串(更常见)是一种表示形式。该符号恰好具有比#xff4023b5
等程序员更容易理解的清晰表示,但它本身是一个可以快速比较的唯一值,但没有(有用的)算术值。 【参考方案3】:
要了解发生了什么,请参阅 Rainer Joswigs 的回答。只需添加一件事:您可以使用*print-case*
控制打印符号的大小写(没有竖线语法):
CL-USER 1 > (let ((*print-case* :downcase))
(format nil "The value is: ~a" 'foo))
"The value is: foo"
CL-USER 2 > (let ((*print-case* :capitalize))
(format nil "The value is: ~a" 'foo))
"The value is: Foo"
CL-USER 3 > (let ((*print-case* :upcase)) ; default
(format nil "The value is: ~a" 'foo))
"The value is: FOO"
【讨论】:
在这些调用之后,print-case 的值是否恢复到原来的值? 是的,*print-case*
是通过用LET
重新绑定来临时重新定义的。如果要永久更改,可以通过(setf *print-case* :downcase)
设置全局变量的值。【参考方案4】:
Lisp 符号,如'a
,不区分大小写。您可以通过以下方式检查...
(eq 'a 'A)
它们是同一个符号。
如果需要区分大小写,应酌情使用字符串或字符。
为了使format
在特定情况下打印符号,您可以根据需要将set the *print-case*
global variable 到:upcase
、:downcase
或:capitalize
。
【讨论】:
clhs.lisp.se/Body/v_pr_cas.htm 您可以将*print-case*
全局设置为:downcase
。
-1 符号区分大小写;例如,考虑|a|
和A
。 'a
等于 'A
的原因是因为 reader 默认情况下会大写符号名称。【参考方案5】:
好的,这可行:
(format nil "The value is: ~a" (string-downcase 'foo))
"The value is: foo"
更好(来自 Rainer)
(format nil "The value is: ~(~a~)" 'foo)
我仍然认为如果意图是表示一个字符串,不应该使用 'foo 而不是“foo”。
【讨论】:
我正在使用 lispworks。我猜小写在其他 lisps 中很常见。 如果你要做一个自我回答,这完全没问题,甚至在这个网站上受到鼓励,试着让它更有信息,而不仅仅是“哦,这就是我的解决方案只为我工作”。你从中学到什么?以上是关于为啥 Lisp 中的单引号总是返回大写?的主要内容,如果未能解决你的问题,请参考以下文章