【问题标题】:Why is Common Lisp case insensitive?为什么 Common Lisp 不区分大小写?
【发布时间】:2011-11-14 14:07:27
【问题描述】:

定义像(defun hi () "Hi!") 这样的函数并能够通过使用(hi)(HI)(Hi)(setf a-number 5) 调用它并能够使用@987654326 访问该号码是否有优势@、A-NUMBERA-Number?

如果有这样的优势,那为什么大多数其他语言都区分大小写?

【问题讨论】:

    标签: common-lisp case-sensitive case-insensitive


    【解决方案1】:

    在交互式会话的代码中使用区分大小写的名称更容易出错。

    Common Lisp 区分大小写。只是 Common Lisp 阅读器功能默认将符号的所有未转义字符转换为大写。这也在 Common Lisp 标准中定义。预定义的 Common Lisp 符号在内部也是全部大写的。

    在旧机器上使用大写字母很常见。请记住,Common Lisp 的设计始于八十年代初(1982 年),其目标是与早期的 Maclisp 兼容,并且需要支持更多类型的计算机(如所谓的迷你计算机和大型机)。旧计算机上使用的其他编程语言也使用大写标识符,例如 COBOL 或 PL/1。

    还请注意,Lisp 经常以交互方式使用,因此在交互式编程会话期间,要正确处理名称的大小写更加困难。当 Lisp 阅读器使用默认大小写(此处为大写)并将所有输入转换为这种大小写时,会稍微容易一些。

    Common Lisp 支持其他阅读器模式,您还可以转义符号:|This is a Symbol with mixed CASE and spaces|

    今天很多软件要么是小写,要么是区分大小写的,首选小写。一些 Lisp 供应商提供了 Common Lisp 的非标准变体,默认情况下所有符号都是小写的,并且阅读器保留大小写。但这使得它与标准 Common Lisp 不兼容,后者的期望是 (symbol-name 'cl:defun) 是“DEFUN”而不是“defun”。

    【讨论】:

      【解决方案2】:

      对于交互式会话,在定义 Common Lisp 标准时,不区分大小写曾经是默认设置。

      但是,真正发生的是 Common Lisp 阅读器在实习和评估之前将所有符号转换为大写。这是默认设置,但您可以随时更改。

      *readtable* 对象有一个属性readtable-case,它控制读取器如何实习和评估读取的符号。你可以setf readtable-case:upcase(默认),:downcase:preserve:invert

      默认情况下,readtable-case 设置为 :upcase,这会导致所有符号都转换为大写。

      如果你想要区分大小写,你应该这样做

      (setf (readtable-case *readtable*) :invert)
      => :invert
      

      乍一看,您可能认为选择 :preserve 选项会更好,但它有一些小问题:标准定义的所有符号都必须大写。因此,您将对仅由您定义的符号区分大小写,并且必须编写:

      * (DEFUN hi () "Hi!")
      => hi
      * (SETF a-number 5)
      => a-number
      * (HI)
      => ;error: the stored function is #'HI in the *readtable*, but by 
         ;       calling (HI) you try to acces a function named #'hi(downcase), which
         ;       gives an error
      * A-NUMBER
      => ;error: same for the variable
      * (hi)
      => "Hi!"
      * a-number
      => 5
      

      :downcase 选项与默认选项相反,将所有内容都转换为小写,不区分大小写。

      但是使用:invert,您在源代码中编写的符号,如defunsetfhi 函数,会被转换为大写,CamelCase 中的任何符号都会像原来一样被保留:

      * (setf (readtable-case *readtable*) :invert)
      => :invert
      * (defun Hi () "Hi!")
      => Hi
      * (Hi)
      => "Hi!"
      * (eq 'Hi 'hi)
      => nil
      * (eq 'HI 'hi)
      => nil
      * (eq 'Hi 'Hi)
      => t
      

      【讨论】:

      • This 澄清了一切。 (setf (readtable-case *readtable*) :invert) 将所有大写字母反转为小写,将所有大写字母反转为小写,因为所有原始函数默认都是大写的。
      【解决方案3】:

      (正如其他人指出的那样,它实际上区分大小写,但标准的阅读器行为是将所有内容大写。)

      关于优点:

      • 您真的希望 HashtableHashTable 命名不同的东西吗?
      • 由于 Common Lisp 提供不同的命名空间,您也不需要大写来区分类、变量和函数名称(以及其他名称)。你可以有一个类name 和一个函数name,没有歧义。 Name 甚至可以是变量的名称,除此之外。
      • 如上一句所示,您可以将散文中的符号名称大写,就像任何其他单词一样。

      【讨论】:

      • 好点!但是如果HashtableHashTable 应该明确指向同一个东西,那么name 不应该也明确指向一个函数、类或变量吗?
      • @wrongusername:这是明确的。当您有一个评估表单(name foo) 时,它无疑是一个函数name;当您拥有(defmethod bar ((baz name)) ...) 时,它无疑是一个类name(或者更确切地说是类型...);当您看到评估表单(quux name) 时,它无疑是一个变量。就像你可以在英语中使用“名称”作为动词和名词而不会混淆一样。
      【解决方案4】:

      默认情况下,CL 中的阅读器是大小写转换,所有转义字符都变成大写。您可以使用readtable-case 自定义此行为。这是因为它易于与遵循相同约定的其他语言交互。

      【讨论】:

      • 嗯,CL 与哪些语言交互?
      • 当时?可能是Fortran。请记住,Common Lisp 及其前身是很久以前在遥远的星系中设计的。
      • 不是特别是 Fortran,而是硬件(电传打字机)通常是大写的,而操作系统使用大写。因此,编程语言也使用大写:PL/1、Cobol、Fortran、Lisp,...在通过慢速连接以行编辑模式连接的终端上编辑区分大小写的命令有点痛苦,...
      • @Rainer 感谢您的洞察力。我假设 Fortran 和其他语言是约定的原因。
      猜你喜欢
      • 2015-12-22
      • 2019-01-18
      • 1970-01-01
      • 1970-01-01
      • 2012-03-10
      • 1970-01-01
      • 2011-11-17
      • 2011-07-27
      • 2018-09-14
      相关资源
      最近更新 更多