合并符号在 Common Lisp 中维护它们的大小写
Merge symbols maintaining their case in Common Lisp
在我的代码中符号必须区分大小写:
(eq 'p 'P)
nil
所以我添加了:
(setf (readtable-case *readtable*) :invert)
在文件的开头并且效果很好。
但我还必须用两个符号制作一个符号(合并它们)
(foo 'K 'm)
Km
到"merge"两个符号我发现了下面的函数
(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)
所以现在在我的 "data base" 我有像 |Km| 这样的东西或 |PHz|这很好。
现在的问题是程序的用户要插入像 Km
或 PHz
这样的东西,我想将它们与我的数据库中的那些进行比较但是:
(eq '|Km| 'Km)
nil
因为 Km
被实习为 KM
而 |Km|
被实习为 |Km|
。
请帮忙
您犯了一些错误,如:
> (setf (readtable-case *readtable*) :invert)
> (symbol-name (symbol-append 'K 'm))
"kM"
当你的符号大小写与你输入的相反时,你会非常兴奋地尝试让它做正确的事情(无论正确的事情是什么,我真的不知道)。您可以 symbol-append
检查可读大小写,并欺骗字符的大小写,但这几乎肯定会在错误的时间发生。
您很可能想要做的是区分您尝试编写的语言(其中符号区分大小写)和您用来实现它的 CL 代码。然后为您尝试编写的语言写一些 reader,这可能就像将 *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)
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
在我的代码中符号必须区分大小写:
(eq 'p 'P)
nil
所以我添加了:
(setf (readtable-case *readtable*) :invert)
在文件的开头并且效果很好。
但我还必须用两个符号制作一个符号(合并它们)
(foo 'K 'm)
Km
到"merge"两个符号我发现了下面的函数 (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)
所以现在在我的 "data base" 我有像 |Km| 这样的东西或 |PHz|这很好。
现在的问题是程序的用户要插入像 Km
或 PHz
这样的东西,我想将它们与我的数据库中的那些进行比较但是:
(eq '|Km| 'Km)
nil
因为 Km
被实习为 KM
而 |Km|
被实习为 |Km|
。
请帮忙
您犯了一些错误,如:
> (setf (readtable-case *readtable*) :invert)
> (symbol-name (symbol-append 'K 'm))
"kM"
当你的符号大小写与你输入的相反时,你会非常兴奋地尝试让它做正确的事情(无论正确的事情是什么,我真的不知道)。您可以 symbol-append
检查可读大小写,并欺骗字符的大小写,但这几乎肯定会在错误的时间发生。
您很可能想要做的是区分您尝试编写的语言(其中符号区分大小写)和您用来实现它的 CL 代码。然后为您尝试编写的语言写一些 reader,这可能就像将 *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)
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