Common lisp Lisp:如何映射汽车#x";为了一张十六进制的列表?

Common lisp Lisp:如何映射汽车#x";为了一张十六进制的列表?,common-lisp,Common Lisp,使用#x。。。如下图所示,可以获得十六进制值的小数 > #xB1 177 > #xA5 165 > #xFF 255 假设我们有一个十六进制列表,使用mapcar#x的正确语法是什么。。。超过名单?以下内容不起作用: > (mapcar #'(lambda (hex) `(#x,hex)) '(B1 A5 FF)) 读卡器错误:a#b/#o/#x/#r宏中的数字格式错误。 [简单错误类型的条件] 谢谢 x是所谓的“读取器宏”。它非常类似于使用引号(即“”)来表示字符

使用#x。。。如下图所示,可以获得十六进制值的小数

> #xB1 
177
> #xA5
165
> #xFF
255
假设我们有一个十六进制列表,使用mapcar#x的正确语法是什么。。。超过名单?以下内容不起作用:

> (mapcar #'(lambda (hex) `(#x,hex)) '(B1 A5 FF))
读卡器错误:a#b/#o/#x/#r宏中的数字格式错误。 [简单错误类型的条件]

谢谢

x是所谓的“读取器宏”。它非常类似于使用引号(即“”)来表示字符串。它们在读取/编译代码时执行。实际上,您需要的是一个可以在运行时从十六进制字符串转换而来的过程。您正在寻找的过程是parse integer,它接受一个字符串并返回它所表示的值。带有它的mapcar应该如下所示:

(mapcar (lambda (hex) 
           (parse-integer hex :radix 16))
        '("B1" "A5" "FF"))
(mapcar (lambda (hex) 
           (parse-integer (symbol-name hex) :radix 16))
        '(B1 A5 FF))
请注意,这是使用字符串,如果您想使用建议中的符号,您必须执行以下操作:

(mapcar (lambda (hex) 
           (parse-integer hex :radix 16))
        '("B1" "A5" "FF"))
(mapcar (lambda (hex) 
           (parse-integer (symbol-name hex) :radix 16))
        '(B1 A5 FF))

如果您不知道符号和字符串之间的区别,我建议您阅读以下内容:

我突然想到,虽然解决这个问题的最佳方法可能是使用中提到的解析整数,但从某种意义上说,这可以通过基于映射的方法来解决

当我们编写类似于
#xB1
的东西时,我们并没有显式地调用函数。相反,我们使用的是一个事实,即
#
是一个分派读取宏字符,并且为子字符
x
安装了一个函数,该函数读取十六进制写入的数字。这意味着,当计算器或编译器获取表单时,数字已经存在。但是,我们可以使用访问处理十六进制字符串的函数。即:

当然,如果你真的想写
#x
,你当然可以定义一个版本,只从长度为2的字符串中提取字符,这样你就可以:

CL-USER> (map-dispatch-macro-character* "#x" '(B1 A5 FF))
(177 165 255)

我发现这也能起作用:>(mapcar#’(lambda(hex)(eval(从string(concatenate'string“#x”(string hex‘‘‘)’)))(B1 A5 FF))所示的尝试显示了对代码如何在Lisp中表示和读取的一个非常基本的误解。请尝试理解读取时间、宏扩展时间、编译时间和运行时间之间的差异。
#x..
无法获取十六进制字符串的十进制值;这是写数字的符号。当读卡器读取
#xB1
时,它返回数字177。然后,REPL对表单177进行求值,表单177对自身进行求值,然后打印表单177。它的印刷方式取决于许多因素。例如,查看如果
(setf*print base*16)
然后评估
#xB1
会发生什么。您将看到打印的
B1
。谢谢#x是reader宏,我知道mapcar的功能,但mapcar到宏这样的概念我不确定;所以我通常可以使用:lambda(macro-thing)(eval(从字符串“…computed macro-thing…”读取)这样就可以实现mapcar-over-reader宏,是正确的吗?它确实可以工作,但效率极低,也是一个巨大的安全漏洞。早期的Lisp有一流的宏(fexpr),但将宏发送到
mapcar
时会出现问题。编译过程非常复杂,最终导致了
defmacro
,它们不是第一类对象。@malisper我完全同意在这里使用
(eval(从字符串读取…)
是非常危险的。不过,可以获得reader宏函数,并使用已知的输入直接调用它。对于这种特定的情况,这并没有那么好,但它可能有助于一般地分派宏字符,所以我添加了这种方法。不过,正如前面提到的,它更脆弱,因为实现不能保证在调用这些函数时所做的假设。
CL-USER> (funcall (get-dispatch-macro-character #\# #\x)
                  (make-string-input-stream "B1")
                  #\x
                  nil)
; Evaluation aborted on #<SB-INT:SIMPLE-READER-ERROR "~A was invoked
; with RECURSIVE-P being true outside of a recursive read operation."
; {1005F245B3}>.  ; in SBCL
(defun map-dispatch-macro-character (disp-char
                                     sub-char
                                     list
                                     &optional (readtable *readtable*))
  "Retrieve the dispatch macro character for DISP-CHAR and SUB-CHAR and
map it over the elements in LIST. Each element in LIST is either a
string designator or a two-element list of a string-designator and a
prefix argument."
  (flet ((to-list (x)
           (if (listp x) x
               (list x))))
    (let ((fn (get-dispatch-macro-character disp-char sub-char readtable)))
      (mapcar (lambda (x)
                (destructuring-bind (str &optional prefix) (to-list x)
                  (with-input-from-string (in (string str))
                    (funcall fn in sub-char prefix))))
              list))))
CL-USER> (map-dispatch-macro-character #\# #\x '(B1 "A5" (FF nil)))
(177 165 255)
CL-USER> (map-dispatch-macro-character* "#x" '(B1 A5 FF))
(177 165 255)