为啥 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 中的单引号总是返回大写?的主要内容,如果未能解决你的问题,请参考以下文章

shell中的单引号,双引号,反引号

为啥我的单引号 (') 没有被编码?

PHP / jQuery - Ajax 调用中的单引号加倍

Java Regex:查找带转义的单引号文本

如何处理 Postgresql 查询中的单引号 [重复]

SQL语句id = '1' OR '1' = 1'单引号为啥不成对?