【问题标题】:Merge symbols maintaining their case in Common Lisp合并符号在 Common Lisp 中保持大小写
【发布时间】:2020-09-08 07:51:32
【问题描述】:

在我的代码中,符号必须区分大小写:

(eq 'p 'P)
nil

所以我添加了:

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

在文件的开头,效果很好。

但我还必须用两个符号制作一个符号(合并它们)

(foo 'K 'm)
Km

“合并”两个符号我发现了以下功能 (here):

(defun symbol-append (&rest symbols) 
  (intern (apply #'concatenate 'string 
                 (mapcar #'symbol-name symbols))))

有效但不维持这种情况:

CL-USER> (symbol-append 'K 'm)
KM

如何在保持大小写的同时合并两个符号?

编辑

'|一些符号|做到了,但我不得不退缩

(setf (readtable-case *readtable*) :upcase)

所以现在在我的“数据库”中我有像 |Km| 这样的东西。或 |PHz|这很好。

现在的问题是程序的用户要插入像 KmPHz 这样的东西,我想与我的数据库中的内容进行比较,但是:

(eq '|Km| 'Km)
nil

因为Km 被实习为KM|Km| 作为|Km|。 请帮忙。

【问题讨论】:

  • 它确实维持这种情况:(symbol-append '|K| '|m|) -> |Km|

标签: lisp common-lisp symbols


【解决方案1】:
CL-USER 34 > (eq 'km '|KM|)
T

CL-USER 35 > (eq 'km '|Km|)
NIL

比较名称不同大小写的两个不同符号。

CL-USER 36 > (let ((a 'km)
                   (b '|Km|))
               (and (eql (symbol-package a)
                         (symbol-package b))
                    (string-equal a b)))
T

【讨论】:

    【解决方案2】:

    你犯了一些错误,如:

    > (setf (readtable-case *readtable*) :invert)
    > (symbol-name (symbol-append 'K 'm))
    "kM"
    

    当您的符号大小写与您输入的内容相反时,您将有一个非常激动人心的时间来尝试使其做正确的事情(无论正确的事情是什么,我真的不知道)。你可以让symbol-append 检查可读的大小写,并欺骗字符的大小写,但这几乎肯定会在错误的时间发生。

    您很可能想要做的是区分您尝试编写的语言(其中符号区分大小写)和您用于实现它的 CL 代码。然后为您尝试编写的语言编写一些阅读器,这可能就像将*readtable* 绑定到区分大小写的语言一样简单(不使用:invert,使用:preserve)。然后您阅读的符号将具有您期望的情况。这可能就像这样简单:

    (defun make-case-preserving-readtable (&optional (from *readtable*))
      (let ((r (copy-readtable from)))
        (setf (readtable-case r) ':preserve)
        r))
    
    (defparameter *case-preserving-readtable* (make-case-preserving-readtable))
    
    (defmacro with-case-preserving-readtable (&body forms)
      `(let ((*readtable* *case-preserving-readtable*))
         ,@forms))
    

    (此代码尝试复制有关当前可读表的任何有用信息,并避免在每次使用宏时都创建一个新表。

    例如:

    > (with-case-preserving-readtable
        (format t "~&in: ")
        (read))
    in: (foo :bar 1 |FOO|)
    (|foo| :|bar| 1 foo)
    

    【讨论】:

    • 我不明白为什么如果这样调用宏将不起作用:(with-case-preserving-readtable 'foo) 它返回FOO
    • @IDK:因为表单是在评估之前读取的:当读取表单时,包括嵌套在其中的任何表单,readtable 是普通的。只有调用read 或使用它的函数(比如load)才会受到它的影响。
    猜你喜欢
    • 2015-12-22
    • 2011-07-27
    • 2011-11-14
    • 1970-01-01
    • 1970-01-01
    • 2017-02-23
    • 2012-04-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多