Lisp: How is MAPCAR "#x" above the HEX list?
Using #x ... as below, the decimal value of the hexadecimal value is obtained
> #xB1 177 > #xA5 165 > #xFF 255 Say we have a hex list, what is the correct syntax using mapcar #x ... above the list? Below does not work:
> (mapcar #'(lambda (hex) `(#x,hex)) '(B1 A5 FF)) Reading error: invalid number in macro # b / # o / # x / # r. [Condition type SIMPLE-ERROR]
Thanks.
#x is what is called a "reader macro". It is very similar to using quotes (i.e. "") to represent strings. They are executed when the code is read / compiled. What you really want is a procedure that can convert from hexadecimal strings at runtime. The procedure you are looking for is a parse-integer, which takes a string and returns the value that it represents. The frame with it should look something like this:
(mapcar (lambda (hex) (parse-integer hex :radix 16)) '("B1" "A5" "FF")) Note that this is using strings, if you want to use characters, as in your sentence, you will need to do something like this:
(mapcar (lambda (hex) (parse-integer (symbol-name hex) :radix 16)) '(B1 A5 FF)) If you do not know the difference between a character and a string, I would suggest reading this: What is a character in a lisp / schema?
It seems to me that although the best solution for this problem is probably to use a parse-integer , as mentioned in response from malisper , there is a sense in which this could be solved using a mapping-based approach.
When we write something like #xB1 , we obviously do not call the function. Instead, we use the fact that # is the character of the send macro to send, and that there is a function for subcharacter x that reads numbers written in hexadecimal format. This means that by the time the evaluator or compiler gets the form, the number already exists. However, we do have access to a function that performs hexadecimal string processing using get-dispatch-macro-character . Viz :.
CL-USER> (get-dispatch-macro-character #\# #\x) #<FUNCTION SB-IMPL::SHARP-X> ; in SBCL CL-USER> (get-dispatch-macro-character #\# #\x) #<SYSTEM-FUNCTION SYSTEM::HEXADECIMAL-READER> ; in CLISP What can we do with this function? How will we use it?
2.1.4.4 Macro Symbols
... If the character is a macro character C1, its function reader macro is the function provided by the implementation. This function reads decimal digits until the digit C2 is read. If the numbers were read, they are converted to the corresponding integer parameter infix P; otherwise, the parameter infix P is nil. the ending small digit C2 is a character (sometimes called a "sub-character" to emphasize its subordinate role in dispatching), which is viewed in the distribution table associated with the dispatching macro symbol C1. The reader macro function associated with the C2 sub-symbol is called by three arguments: stream, C2 sub-symbol, and infix P. For more information on sending characters, see the Shock-macro character set function.
This means that when we write something like #xB1 , the function above receives a call with a stream from which it can read B1 , the character x and nil . We can try to call this function with such arguments, although we cannot be absolutely sure what will happen, because implementations may make different assumptions about where the function will be called from.
For example, this works without problems in CLISP, but SBCL suggests that the function should be called recursively from read (which we do not):
CL-USER> (funcall (get-dispatch-macro-character #\# #\x) (make-string-input-stream "B1") #\x nil) 177 ; in CLISP 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 However, for implementations where this will work, we can easily write a mapcar function to extract the send send macro function and map it over some lines. So in the implementation where this works:
(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) And of course, if you really want to write #x , you can, of course, define a version that simply extracts characters from a string two in length so you can:
CL-USER> (map-dispatch-macro-character* "#x" '(B1 A5 FF)) (177 165 255)