Common Lisp add suffix to symbol for use in macros
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}
How do you introduce new, predictably named identifiers with suffixes in a macro?
So, I'm writing a simple library for manipulating quaternions. I'm using the simplest representation that could possibly work, a list of components, for the time being, but I'd like to define a simple API that doesn't depend on that representation.
When defining algorithms, I want to refer to each of the components of the quaternion with a predictable name like somesymbol-realpart
or somesymbol-i
.
I'd like to be able to get the following snippet to work.
(let
((my-quat '(1 2 3 4)))
(with-quaternion my-quat
(assert-equalp 1 my-quat-realpart)
(assert-equalp 2 my-quat-i)
(assert-equalp 3 my-quat-j)
(assert-equalp 4 my-quat-k)))
However, the method I used for producing a symbol with a suffix seems to produce strange case-sensitive symbols with escaped uppercase characters.
(defun add-suffix-to-symbol (sym suffix)
(intern (concatenate 'string "" (string sym) "-" suffix)))
As a result of converting a symbol to a string, it is printed in uppercase... which is a totally valid canonicalization. However, creating a new symbol via intern
preserves the case for some reason, so I have to do something like the following to refer to bindings introduced by with-quaternion
.
(let
((my-quat '(1 2 3 4)))
(with-quaternion my-quat
(assert-equalp 1 |MY-QUAT-realpart|)
(assert-equalp 2 |MY-QUAT-i|)
(assert-equalp 3 |MY-QUAT-j|)
(assert-equalp 4 |MY-QUAT-k|)))
How do I create a new symbol that's identical to an old one but with a suffix so that it can be used in a macro?
for reference, here is all the code.
(defun assert-equalp (e a)
(assert (equalp e a)))
(defun quat-realpart (q)
(first q))
(defun quat-i (q)
(second q))
(defun quat-j (q)
(third q))
(defun quat-k (q)
(fourth q))
(assert-equalp '1 (quat-realpart '(1 2 3 4)))
(assert-equalp '2 (quat-i '(1 2 3 4)))
(assert-equalp '3 (quat-j '(1 2 3 4)))
(assert-equalp '4 (quat-k '(1 2 3 4)))
(defun add-suffix-to-symbol (sym suffix)
(intern (concatenate 'string "" (string sym) "-" suffix)))
(print (add-suffix-to-symbol 'a "suffix"))
(defgeneric with-quaternion-impl (q-sym body))
(defmethod with-quaternion-impl ((q-sym symbol) body)
(let
((q-realpart (add-suffix-to-symbol q-sym "realpart"))
(q-i (add-suffix-to-symbol q-sym "i"))
(q-j (add-suffix-to-symbol q-sym "j"))
(q-k (add-suffix-to-symbol q-sym "k")))
`(let
((,q-realpart (quat-realpart ,q-sym))
(,q-i (quat-i ,q-sym))
(,q-j (quat-j ,q-sym))
(,q-k (quat-k ,q-sym)))
(progn ,@body))))
(defmacro with-quaternion (q-sym &rest body)
(with-quaternion-impl q-sym body))
(let
((my-quat '(1 2 3 4)))
(with-quaternion my-quat
(assert-equalp 1 |MY-QUAT-realpart|)
(assert-equalp 2 |MY-QUAT-i|)
(assert-equalp 3 |MY-QUAT-j|)
(assert-equalp 4 |MY-QUAT-k|)))
(let
((my-quat '(1 2 3 4)))
(with-quaternion my-quat
(assert-equalp 1 my-quat-realpart)
(assert-equalp 2 my-quat-i)
(assert-equalp 3 my-quat-j)
(assert-equalp 4 my-quat-k)))
When run under clisp
, it prints the following symbol, clearly with escaped uppercase characters.
|A-suffix|
and produces the following error message:
*** - PROGN: variable MY-QUAT-REALPART has no value
common-lisp
add a comment |
How do you introduce new, predictably named identifiers with suffixes in a macro?
So, I'm writing a simple library for manipulating quaternions. I'm using the simplest representation that could possibly work, a list of components, for the time being, but I'd like to define a simple API that doesn't depend on that representation.
When defining algorithms, I want to refer to each of the components of the quaternion with a predictable name like somesymbol-realpart
or somesymbol-i
.
I'd like to be able to get the following snippet to work.
(let
((my-quat '(1 2 3 4)))
(with-quaternion my-quat
(assert-equalp 1 my-quat-realpart)
(assert-equalp 2 my-quat-i)
(assert-equalp 3 my-quat-j)
(assert-equalp 4 my-quat-k)))
However, the method I used for producing a symbol with a suffix seems to produce strange case-sensitive symbols with escaped uppercase characters.
(defun add-suffix-to-symbol (sym suffix)
(intern (concatenate 'string "" (string sym) "-" suffix)))
As a result of converting a symbol to a string, it is printed in uppercase... which is a totally valid canonicalization. However, creating a new symbol via intern
preserves the case for some reason, so I have to do something like the following to refer to bindings introduced by with-quaternion
.
(let
((my-quat '(1 2 3 4)))
(with-quaternion my-quat
(assert-equalp 1 |MY-QUAT-realpart|)
(assert-equalp 2 |MY-QUAT-i|)
(assert-equalp 3 |MY-QUAT-j|)
(assert-equalp 4 |MY-QUAT-k|)))
How do I create a new symbol that's identical to an old one but with a suffix so that it can be used in a macro?
for reference, here is all the code.
(defun assert-equalp (e a)
(assert (equalp e a)))
(defun quat-realpart (q)
(first q))
(defun quat-i (q)
(second q))
(defun quat-j (q)
(third q))
(defun quat-k (q)
(fourth q))
(assert-equalp '1 (quat-realpart '(1 2 3 4)))
(assert-equalp '2 (quat-i '(1 2 3 4)))
(assert-equalp '3 (quat-j '(1 2 3 4)))
(assert-equalp '4 (quat-k '(1 2 3 4)))
(defun add-suffix-to-symbol (sym suffix)
(intern (concatenate 'string "" (string sym) "-" suffix)))
(print (add-suffix-to-symbol 'a "suffix"))
(defgeneric with-quaternion-impl (q-sym body))
(defmethod with-quaternion-impl ((q-sym symbol) body)
(let
((q-realpart (add-suffix-to-symbol q-sym "realpart"))
(q-i (add-suffix-to-symbol q-sym "i"))
(q-j (add-suffix-to-symbol q-sym "j"))
(q-k (add-suffix-to-symbol q-sym "k")))
`(let
((,q-realpart (quat-realpart ,q-sym))
(,q-i (quat-i ,q-sym))
(,q-j (quat-j ,q-sym))
(,q-k (quat-k ,q-sym)))
(progn ,@body))))
(defmacro with-quaternion (q-sym &rest body)
(with-quaternion-impl q-sym body))
(let
((my-quat '(1 2 3 4)))
(with-quaternion my-quat
(assert-equalp 1 |MY-QUAT-realpart|)
(assert-equalp 2 |MY-QUAT-i|)
(assert-equalp 3 |MY-QUAT-j|)
(assert-equalp 4 |MY-QUAT-k|)))
(let
((my-quat '(1 2 3 4)))
(with-quaternion my-quat
(assert-equalp 1 my-quat-realpart)
(assert-equalp 2 my-quat-i)
(assert-equalp 3 my-quat-j)
(assert-equalp 4 my-quat-k)))
When run under clisp
, it prints the following symbol, clearly with escaped uppercase characters.
|A-suffix|
and produces the following error message:
*** - PROGN: variable MY-QUAT-REALPART has no value
common-lisp
add a comment |
How do you introduce new, predictably named identifiers with suffixes in a macro?
So, I'm writing a simple library for manipulating quaternions. I'm using the simplest representation that could possibly work, a list of components, for the time being, but I'd like to define a simple API that doesn't depend on that representation.
When defining algorithms, I want to refer to each of the components of the quaternion with a predictable name like somesymbol-realpart
or somesymbol-i
.
I'd like to be able to get the following snippet to work.
(let
((my-quat '(1 2 3 4)))
(with-quaternion my-quat
(assert-equalp 1 my-quat-realpart)
(assert-equalp 2 my-quat-i)
(assert-equalp 3 my-quat-j)
(assert-equalp 4 my-quat-k)))
However, the method I used for producing a symbol with a suffix seems to produce strange case-sensitive symbols with escaped uppercase characters.
(defun add-suffix-to-symbol (sym suffix)
(intern (concatenate 'string "" (string sym) "-" suffix)))
As a result of converting a symbol to a string, it is printed in uppercase... which is a totally valid canonicalization. However, creating a new symbol via intern
preserves the case for some reason, so I have to do something like the following to refer to bindings introduced by with-quaternion
.
(let
((my-quat '(1 2 3 4)))
(with-quaternion my-quat
(assert-equalp 1 |MY-QUAT-realpart|)
(assert-equalp 2 |MY-QUAT-i|)
(assert-equalp 3 |MY-QUAT-j|)
(assert-equalp 4 |MY-QUAT-k|)))
How do I create a new symbol that's identical to an old one but with a suffix so that it can be used in a macro?
for reference, here is all the code.
(defun assert-equalp (e a)
(assert (equalp e a)))
(defun quat-realpart (q)
(first q))
(defun quat-i (q)
(second q))
(defun quat-j (q)
(third q))
(defun quat-k (q)
(fourth q))
(assert-equalp '1 (quat-realpart '(1 2 3 4)))
(assert-equalp '2 (quat-i '(1 2 3 4)))
(assert-equalp '3 (quat-j '(1 2 3 4)))
(assert-equalp '4 (quat-k '(1 2 3 4)))
(defun add-suffix-to-symbol (sym suffix)
(intern (concatenate 'string "" (string sym) "-" suffix)))
(print (add-suffix-to-symbol 'a "suffix"))
(defgeneric with-quaternion-impl (q-sym body))
(defmethod with-quaternion-impl ((q-sym symbol) body)
(let
((q-realpart (add-suffix-to-symbol q-sym "realpart"))
(q-i (add-suffix-to-symbol q-sym "i"))
(q-j (add-suffix-to-symbol q-sym "j"))
(q-k (add-suffix-to-symbol q-sym "k")))
`(let
((,q-realpart (quat-realpart ,q-sym))
(,q-i (quat-i ,q-sym))
(,q-j (quat-j ,q-sym))
(,q-k (quat-k ,q-sym)))
(progn ,@body))))
(defmacro with-quaternion (q-sym &rest body)
(with-quaternion-impl q-sym body))
(let
((my-quat '(1 2 3 4)))
(with-quaternion my-quat
(assert-equalp 1 |MY-QUAT-realpart|)
(assert-equalp 2 |MY-QUAT-i|)
(assert-equalp 3 |MY-QUAT-j|)
(assert-equalp 4 |MY-QUAT-k|)))
(let
((my-quat '(1 2 3 4)))
(with-quaternion my-quat
(assert-equalp 1 my-quat-realpart)
(assert-equalp 2 my-quat-i)
(assert-equalp 3 my-quat-j)
(assert-equalp 4 my-quat-k)))
When run under clisp
, it prints the following symbol, clearly with escaped uppercase characters.
|A-suffix|
and produces the following error message:
*** - PROGN: variable MY-QUAT-REALPART has no value
common-lisp
How do you introduce new, predictably named identifiers with suffixes in a macro?
So, I'm writing a simple library for manipulating quaternions. I'm using the simplest representation that could possibly work, a list of components, for the time being, but I'd like to define a simple API that doesn't depend on that representation.
When defining algorithms, I want to refer to each of the components of the quaternion with a predictable name like somesymbol-realpart
or somesymbol-i
.
I'd like to be able to get the following snippet to work.
(let
((my-quat '(1 2 3 4)))
(with-quaternion my-quat
(assert-equalp 1 my-quat-realpart)
(assert-equalp 2 my-quat-i)
(assert-equalp 3 my-quat-j)
(assert-equalp 4 my-quat-k)))
However, the method I used for producing a symbol with a suffix seems to produce strange case-sensitive symbols with escaped uppercase characters.
(defun add-suffix-to-symbol (sym suffix)
(intern (concatenate 'string "" (string sym) "-" suffix)))
As a result of converting a symbol to a string, it is printed in uppercase... which is a totally valid canonicalization. However, creating a new symbol via intern
preserves the case for some reason, so I have to do something like the following to refer to bindings introduced by with-quaternion
.
(let
((my-quat '(1 2 3 4)))
(with-quaternion my-quat
(assert-equalp 1 |MY-QUAT-realpart|)
(assert-equalp 2 |MY-QUAT-i|)
(assert-equalp 3 |MY-QUAT-j|)
(assert-equalp 4 |MY-QUAT-k|)))
How do I create a new symbol that's identical to an old one but with a suffix so that it can be used in a macro?
for reference, here is all the code.
(defun assert-equalp (e a)
(assert (equalp e a)))
(defun quat-realpart (q)
(first q))
(defun quat-i (q)
(second q))
(defun quat-j (q)
(third q))
(defun quat-k (q)
(fourth q))
(assert-equalp '1 (quat-realpart '(1 2 3 4)))
(assert-equalp '2 (quat-i '(1 2 3 4)))
(assert-equalp '3 (quat-j '(1 2 3 4)))
(assert-equalp '4 (quat-k '(1 2 3 4)))
(defun add-suffix-to-symbol (sym suffix)
(intern (concatenate 'string "" (string sym) "-" suffix)))
(print (add-suffix-to-symbol 'a "suffix"))
(defgeneric with-quaternion-impl (q-sym body))
(defmethod with-quaternion-impl ((q-sym symbol) body)
(let
((q-realpart (add-suffix-to-symbol q-sym "realpart"))
(q-i (add-suffix-to-symbol q-sym "i"))
(q-j (add-suffix-to-symbol q-sym "j"))
(q-k (add-suffix-to-symbol q-sym "k")))
`(let
((,q-realpart (quat-realpart ,q-sym))
(,q-i (quat-i ,q-sym))
(,q-j (quat-j ,q-sym))
(,q-k (quat-k ,q-sym)))
(progn ,@body))))
(defmacro with-quaternion (q-sym &rest body)
(with-quaternion-impl q-sym body))
(let
((my-quat '(1 2 3 4)))
(with-quaternion my-quat
(assert-equalp 1 |MY-QUAT-realpart|)
(assert-equalp 2 |MY-QUAT-i|)
(assert-equalp 3 |MY-QUAT-j|)
(assert-equalp 4 |MY-QUAT-k|)))
(let
((my-quat '(1 2 3 4)))
(with-quaternion my-quat
(assert-equalp 1 my-quat-realpart)
(assert-equalp 2 my-quat-i)
(assert-equalp 3 my-quat-j)
(assert-equalp 4 my-quat-k)))
When run under clisp
, it prints the following symbol, clearly with escaped uppercase characters.
|A-suffix|
and produces the following error message:
*** - PROGN: variable MY-QUAT-REALPART has no value
common-lisp
common-lisp
asked Nov 23 '18 at 23:41
Gregory NisbetGregory Nisbet
3,23121334
3,23121334
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
Symbols in common lisp are interned in uppercase by default. The apparent case insensitivity is because everything you type is converted to uppercase at read/retrieval time, unless you use the special syntax with bar characters |My-case-sensitive-SYMBOL|
. my-case-insensitive-symbol
and MY-CASE-INSENSITIVE-SYMBOL
refer to the same interned symbol, which is stored in all uppercase (though, this being common lisp, it is often possible to change that with command line options and reader macros). The symbol is actually not case insensitive at all, it just appears that way because most of the symbols in your code are uppercased by the reader, unless you specially exempt them from that by surrounding them in bar characters or purposely configuring an environment with unusual reader options.
The net effect of all the above is that if you want to access a macro-generated symbol using the more familiar syntax, be sure to have all components uppercased before it's interned, e.g.:
(add-suffix-to-symbol q-sym "I")
instead of
(add-suffix-to-symbol q-sym "i")
Another option is to pass symbols to be concatenated rather than strings, e.g.
(defun add-suffix-to-symbol (sym suffix)
(intern (concatenate 'string "" (string sym) "-" (string suffix))))
(print (add-suffix-to-symbol 'FOO 'bar)) ; foo-bar
(print (add-suffix-to-symbol 'foo '|bar|)) ; |FOO-bar| because foo is converted to FOO at read time
add a comment |
To add a bit to Joe's answer:
Symbols are a datatype with names, values, a property list and they may be interned in a package (another Lisp data structure).
Symbols preserve their namestring cases
You can create a symbol with its name from a string and also ask for the name of the symbol. A function to make a symbol is, well, make-symbol
:
CL-USER 8 > (make-symbol "This is A Symbol!!!***")
#:|This is A Symbol!!!***|
CL-USER 9 > (symbol-name (make-symbol "This is A Symbol!!!***"))
"This is A Symbol!!!***"
As you see the string is used as is and we get it out as it was provided. There is no case conversion.
Escaping a symbol for the reader
To print a symbol with different cases, whitespace and or special characters the symbol is escaped with surrounding |
or single :
CL-USER 11 > '|foo BAR ***# <>|
|foo BAR ***# <>|
CL-USER 12 > 'foo BAR ***# <>
|foo BAR ***# <>|
The reader is by default uppercasing unescaped input for symbol names
The Lisp reader may use functions like find-symbol
or intern
to find or create symbols. Both can take a string as input and they are also case sensitive:
CL-USER 15 > (let ((symbol '|foo|))
(eq (find-symbol "FOO") symbol))
NIL
But the reader itself (used for example via read
and read-from-string
) is not case sensitive by default. By default all symbols get uppercased:
CL-USER 21 > (symbol-name 'foo)
"FOO"
CL-USER 22 > (symbol-name 'FOO)
"FOO"
CL-USER 23 > (eq 'foo 'FOO)
T
We can check that both the printer and the reader are using uppercase by default:
CL-USER 35 > *print-case*
:UPCASE
CL-USER 36 > (readtable-case *readtable*)
:UPCASE
When creating symbols in macros we usually want uppercase strings
This means that when one creates symbols with names from strings, then one usually wants uppercase strings as input:
lowercase:
CL-USER 25 > (intern "zippy")
|zippy|
NIL
uppercase:
CL-USER 26 > (intern "ZIPPY")
ZIPPY
NIL
In data we sometimes want mixed case symbols: escape them
Sometimes we want to work with different cases: for example when the case needs to preserved because it is used as data:
CL-USER 27 > (defvar *parents* '(|Eva Luator| |Ben BitDiddle jr.|))
*PARENTS*
CL-USER 28 > *parents*
(|Eva Luator| |Ben BitDiddle jr.|)
Creating uppercased symbol names with format
Often in code one creates symbol names with format
- which might be more concise than concatenate
. One can then use format
control strings, where the text or parts of it are uppercased by using ~:@(
and ~)
:
CL-USER 33 > (format nil "~:@(~a-~a-~a~)" "my" "macro" "name")
"MY-MACRO-NAME"
CL-USER 34 > (intern (format nil "~:@(~a-~a-~a~)" "my" "macro" "name"))
MY-MACRO-NAME
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53453935%2fcommon-lisp-add-suffix-to-symbol-for-use-in-macros%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
Symbols in common lisp are interned in uppercase by default. The apparent case insensitivity is because everything you type is converted to uppercase at read/retrieval time, unless you use the special syntax with bar characters |My-case-sensitive-SYMBOL|
. my-case-insensitive-symbol
and MY-CASE-INSENSITIVE-SYMBOL
refer to the same interned symbol, which is stored in all uppercase (though, this being common lisp, it is often possible to change that with command line options and reader macros). The symbol is actually not case insensitive at all, it just appears that way because most of the symbols in your code are uppercased by the reader, unless you specially exempt them from that by surrounding them in bar characters or purposely configuring an environment with unusual reader options.
The net effect of all the above is that if you want to access a macro-generated symbol using the more familiar syntax, be sure to have all components uppercased before it's interned, e.g.:
(add-suffix-to-symbol q-sym "I")
instead of
(add-suffix-to-symbol q-sym "i")
Another option is to pass symbols to be concatenated rather than strings, e.g.
(defun add-suffix-to-symbol (sym suffix)
(intern (concatenate 'string "" (string sym) "-" (string suffix))))
(print (add-suffix-to-symbol 'FOO 'bar)) ; foo-bar
(print (add-suffix-to-symbol 'foo '|bar|)) ; |FOO-bar| because foo is converted to FOO at read time
add a comment |
Symbols in common lisp are interned in uppercase by default. The apparent case insensitivity is because everything you type is converted to uppercase at read/retrieval time, unless you use the special syntax with bar characters |My-case-sensitive-SYMBOL|
. my-case-insensitive-symbol
and MY-CASE-INSENSITIVE-SYMBOL
refer to the same interned symbol, which is stored in all uppercase (though, this being common lisp, it is often possible to change that with command line options and reader macros). The symbol is actually not case insensitive at all, it just appears that way because most of the symbols in your code are uppercased by the reader, unless you specially exempt them from that by surrounding them in bar characters or purposely configuring an environment with unusual reader options.
The net effect of all the above is that if you want to access a macro-generated symbol using the more familiar syntax, be sure to have all components uppercased before it's interned, e.g.:
(add-suffix-to-symbol q-sym "I")
instead of
(add-suffix-to-symbol q-sym "i")
Another option is to pass symbols to be concatenated rather than strings, e.g.
(defun add-suffix-to-symbol (sym suffix)
(intern (concatenate 'string "" (string sym) "-" (string suffix))))
(print (add-suffix-to-symbol 'FOO 'bar)) ; foo-bar
(print (add-suffix-to-symbol 'foo '|bar|)) ; |FOO-bar| because foo is converted to FOO at read time
add a comment |
Symbols in common lisp are interned in uppercase by default. The apparent case insensitivity is because everything you type is converted to uppercase at read/retrieval time, unless you use the special syntax with bar characters |My-case-sensitive-SYMBOL|
. my-case-insensitive-symbol
and MY-CASE-INSENSITIVE-SYMBOL
refer to the same interned symbol, which is stored in all uppercase (though, this being common lisp, it is often possible to change that with command line options and reader macros). The symbol is actually not case insensitive at all, it just appears that way because most of the symbols in your code are uppercased by the reader, unless you specially exempt them from that by surrounding them in bar characters or purposely configuring an environment with unusual reader options.
The net effect of all the above is that if you want to access a macro-generated symbol using the more familiar syntax, be sure to have all components uppercased before it's interned, e.g.:
(add-suffix-to-symbol q-sym "I")
instead of
(add-suffix-to-symbol q-sym "i")
Another option is to pass symbols to be concatenated rather than strings, e.g.
(defun add-suffix-to-symbol (sym suffix)
(intern (concatenate 'string "" (string sym) "-" (string suffix))))
(print (add-suffix-to-symbol 'FOO 'bar)) ; foo-bar
(print (add-suffix-to-symbol 'foo '|bar|)) ; |FOO-bar| because foo is converted to FOO at read time
Symbols in common lisp are interned in uppercase by default. The apparent case insensitivity is because everything you type is converted to uppercase at read/retrieval time, unless you use the special syntax with bar characters |My-case-sensitive-SYMBOL|
. my-case-insensitive-symbol
and MY-CASE-INSENSITIVE-SYMBOL
refer to the same interned symbol, which is stored in all uppercase (though, this being common lisp, it is often possible to change that with command line options and reader macros). The symbol is actually not case insensitive at all, it just appears that way because most of the symbols in your code are uppercased by the reader, unless you specially exempt them from that by surrounding them in bar characters or purposely configuring an environment with unusual reader options.
The net effect of all the above is that if you want to access a macro-generated symbol using the more familiar syntax, be sure to have all components uppercased before it's interned, e.g.:
(add-suffix-to-symbol q-sym "I")
instead of
(add-suffix-to-symbol q-sym "i")
Another option is to pass symbols to be concatenated rather than strings, e.g.
(defun add-suffix-to-symbol (sym suffix)
(intern (concatenate 'string "" (string sym) "-" (string suffix))))
(print (add-suffix-to-symbol 'FOO 'bar)) ; foo-bar
(print (add-suffix-to-symbol 'foo '|bar|)) ; |FOO-bar| because foo is converted to FOO at read time
edited Nov 24 '18 at 0:10
answered Nov 23 '18 at 23:58
Joe TaylorJoe Taylor
763
763
add a comment |
add a comment |
To add a bit to Joe's answer:
Symbols are a datatype with names, values, a property list and they may be interned in a package (another Lisp data structure).
Symbols preserve their namestring cases
You can create a symbol with its name from a string and also ask for the name of the symbol. A function to make a symbol is, well, make-symbol
:
CL-USER 8 > (make-symbol "This is A Symbol!!!***")
#:|This is A Symbol!!!***|
CL-USER 9 > (symbol-name (make-symbol "This is A Symbol!!!***"))
"This is A Symbol!!!***"
As you see the string is used as is and we get it out as it was provided. There is no case conversion.
Escaping a symbol for the reader
To print a symbol with different cases, whitespace and or special characters the symbol is escaped with surrounding |
or single :
CL-USER 11 > '|foo BAR ***# <>|
|foo BAR ***# <>|
CL-USER 12 > 'foo BAR ***# <>
|foo BAR ***# <>|
The reader is by default uppercasing unescaped input for symbol names
The Lisp reader may use functions like find-symbol
or intern
to find or create symbols. Both can take a string as input and they are also case sensitive:
CL-USER 15 > (let ((symbol '|foo|))
(eq (find-symbol "FOO") symbol))
NIL
But the reader itself (used for example via read
and read-from-string
) is not case sensitive by default. By default all symbols get uppercased:
CL-USER 21 > (symbol-name 'foo)
"FOO"
CL-USER 22 > (symbol-name 'FOO)
"FOO"
CL-USER 23 > (eq 'foo 'FOO)
T
We can check that both the printer and the reader are using uppercase by default:
CL-USER 35 > *print-case*
:UPCASE
CL-USER 36 > (readtable-case *readtable*)
:UPCASE
When creating symbols in macros we usually want uppercase strings
This means that when one creates symbols with names from strings, then one usually wants uppercase strings as input:
lowercase:
CL-USER 25 > (intern "zippy")
|zippy|
NIL
uppercase:
CL-USER 26 > (intern "ZIPPY")
ZIPPY
NIL
In data we sometimes want mixed case symbols: escape them
Sometimes we want to work with different cases: for example when the case needs to preserved because it is used as data:
CL-USER 27 > (defvar *parents* '(|Eva Luator| |Ben BitDiddle jr.|))
*PARENTS*
CL-USER 28 > *parents*
(|Eva Luator| |Ben BitDiddle jr.|)
Creating uppercased symbol names with format
Often in code one creates symbol names with format
- which might be more concise than concatenate
. One can then use format
control strings, where the text or parts of it are uppercased by using ~:@(
and ~)
:
CL-USER 33 > (format nil "~:@(~a-~a-~a~)" "my" "macro" "name")
"MY-MACRO-NAME"
CL-USER 34 > (intern (format nil "~:@(~a-~a-~a~)" "my" "macro" "name"))
MY-MACRO-NAME
add a comment |
To add a bit to Joe's answer:
Symbols are a datatype with names, values, a property list and they may be interned in a package (another Lisp data structure).
Symbols preserve their namestring cases
You can create a symbol with its name from a string and also ask for the name of the symbol. A function to make a symbol is, well, make-symbol
:
CL-USER 8 > (make-symbol "This is A Symbol!!!***")
#:|This is A Symbol!!!***|
CL-USER 9 > (symbol-name (make-symbol "This is A Symbol!!!***"))
"This is A Symbol!!!***"
As you see the string is used as is and we get it out as it was provided. There is no case conversion.
Escaping a symbol for the reader
To print a symbol with different cases, whitespace and or special characters the symbol is escaped with surrounding |
or single :
CL-USER 11 > '|foo BAR ***# <>|
|foo BAR ***# <>|
CL-USER 12 > 'foo BAR ***# <>
|foo BAR ***# <>|
The reader is by default uppercasing unescaped input for symbol names
The Lisp reader may use functions like find-symbol
or intern
to find or create symbols. Both can take a string as input and they are also case sensitive:
CL-USER 15 > (let ((symbol '|foo|))
(eq (find-symbol "FOO") symbol))
NIL
But the reader itself (used for example via read
and read-from-string
) is not case sensitive by default. By default all symbols get uppercased:
CL-USER 21 > (symbol-name 'foo)
"FOO"
CL-USER 22 > (symbol-name 'FOO)
"FOO"
CL-USER 23 > (eq 'foo 'FOO)
T
We can check that both the printer and the reader are using uppercase by default:
CL-USER 35 > *print-case*
:UPCASE
CL-USER 36 > (readtable-case *readtable*)
:UPCASE
When creating symbols in macros we usually want uppercase strings
This means that when one creates symbols with names from strings, then one usually wants uppercase strings as input:
lowercase:
CL-USER 25 > (intern "zippy")
|zippy|
NIL
uppercase:
CL-USER 26 > (intern "ZIPPY")
ZIPPY
NIL
In data we sometimes want mixed case symbols: escape them
Sometimes we want to work with different cases: for example when the case needs to preserved because it is used as data:
CL-USER 27 > (defvar *parents* '(|Eva Luator| |Ben BitDiddle jr.|))
*PARENTS*
CL-USER 28 > *parents*
(|Eva Luator| |Ben BitDiddle jr.|)
Creating uppercased symbol names with format
Often in code one creates symbol names with format
- which might be more concise than concatenate
. One can then use format
control strings, where the text or parts of it are uppercased by using ~:@(
and ~)
:
CL-USER 33 > (format nil "~:@(~a-~a-~a~)" "my" "macro" "name")
"MY-MACRO-NAME"
CL-USER 34 > (intern (format nil "~:@(~a-~a-~a~)" "my" "macro" "name"))
MY-MACRO-NAME
add a comment |
To add a bit to Joe's answer:
Symbols are a datatype with names, values, a property list and they may be interned in a package (another Lisp data structure).
Symbols preserve their namestring cases
You can create a symbol with its name from a string and also ask for the name of the symbol. A function to make a symbol is, well, make-symbol
:
CL-USER 8 > (make-symbol "This is A Symbol!!!***")
#:|This is A Symbol!!!***|
CL-USER 9 > (symbol-name (make-symbol "This is A Symbol!!!***"))
"This is A Symbol!!!***"
As you see the string is used as is and we get it out as it was provided. There is no case conversion.
Escaping a symbol for the reader
To print a symbol with different cases, whitespace and or special characters the symbol is escaped with surrounding |
or single :
CL-USER 11 > '|foo BAR ***# <>|
|foo BAR ***# <>|
CL-USER 12 > 'foo BAR ***# <>
|foo BAR ***# <>|
The reader is by default uppercasing unescaped input for symbol names
The Lisp reader may use functions like find-symbol
or intern
to find or create symbols. Both can take a string as input and they are also case sensitive:
CL-USER 15 > (let ((symbol '|foo|))
(eq (find-symbol "FOO") symbol))
NIL
But the reader itself (used for example via read
and read-from-string
) is not case sensitive by default. By default all symbols get uppercased:
CL-USER 21 > (symbol-name 'foo)
"FOO"
CL-USER 22 > (symbol-name 'FOO)
"FOO"
CL-USER 23 > (eq 'foo 'FOO)
T
We can check that both the printer and the reader are using uppercase by default:
CL-USER 35 > *print-case*
:UPCASE
CL-USER 36 > (readtable-case *readtable*)
:UPCASE
When creating symbols in macros we usually want uppercase strings
This means that when one creates symbols with names from strings, then one usually wants uppercase strings as input:
lowercase:
CL-USER 25 > (intern "zippy")
|zippy|
NIL
uppercase:
CL-USER 26 > (intern "ZIPPY")
ZIPPY
NIL
In data we sometimes want mixed case symbols: escape them
Sometimes we want to work with different cases: for example when the case needs to preserved because it is used as data:
CL-USER 27 > (defvar *parents* '(|Eva Luator| |Ben BitDiddle jr.|))
*PARENTS*
CL-USER 28 > *parents*
(|Eva Luator| |Ben BitDiddle jr.|)
Creating uppercased symbol names with format
Often in code one creates symbol names with format
- which might be more concise than concatenate
. One can then use format
control strings, where the text or parts of it are uppercased by using ~:@(
and ~)
:
CL-USER 33 > (format nil "~:@(~a-~a-~a~)" "my" "macro" "name")
"MY-MACRO-NAME"
CL-USER 34 > (intern (format nil "~:@(~a-~a-~a~)" "my" "macro" "name"))
MY-MACRO-NAME
To add a bit to Joe's answer:
Symbols are a datatype with names, values, a property list and they may be interned in a package (another Lisp data structure).
Symbols preserve their namestring cases
You can create a symbol with its name from a string and also ask for the name of the symbol. A function to make a symbol is, well, make-symbol
:
CL-USER 8 > (make-symbol "This is A Symbol!!!***")
#:|This is A Symbol!!!***|
CL-USER 9 > (symbol-name (make-symbol "This is A Symbol!!!***"))
"This is A Symbol!!!***"
As you see the string is used as is and we get it out as it was provided. There is no case conversion.
Escaping a symbol for the reader
To print a symbol with different cases, whitespace and or special characters the symbol is escaped with surrounding |
or single :
CL-USER 11 > '|foo BAR ***# <>|
|foo BAR ***# <>|
CL-USER 12 > 'foo BAR ***# <>
|foo BAR ***# <>|
The reader is by default uppercasing unescaped input for symbol names
The Lisp reader may use functions like find-symbol
or intern
to find or create symbols. Both can take a string as input and they are also case sensitive:
CL-USER 15 > (let ((symbol '|foo|))
(eq (find-symbol "FOO") symbol))
NIL
But the reader itself (used for example via read
and read-from-string
) is not case sensitive by default. By default all symbols get uppercased:
CL-USER 21 > (symbol-name 'foo)
"FOO"
CL-USER 22 > (symbol-name 'FOO)
"FOO"
CL-USER 23 > (eq 'foo 'FOO)
T
We can check that both the printer and the reader are using uppercase by default:
CL-USER 35 > *print-case*
:UPCASE
CL-USER 36 > (readtable-case *readtable*)
:UPCASE
When creating symbols in macros we usually want uppercase strings
This means that when one creates symbols with names from strings, then one usually wants uppercase strings as input:
lowercase:
CL-USER 25 > (intern "zippy")
|zippy|
NIL
uppercase:
CL-USER 26 > (intern "ZIPPY")
ZIPPY
NIL
In data we sometimes want mixed case symbols: escape them
Sometimes we want to work with different cases: for example when the case needs to preserved because it is used as data:
CL-USER 27 > (defvar *parents* '(|Eva Luator| |Ben BitDiddle jr.|))
*PARENTS*
CL-USER 28 > *parents*
(|Eva Luator| |Ben BitDiddle jr.|)
Creating uppercased symbol names with format
Often in code one creates symbol names with format
- which might be more concise than concatenate
. One can then use format
control strings, where the text or parts of it are uppercased by using ~:@(
and ~)
:
CL-USER 33 > (format nil "~:@(~a-~a-~a~)" "my" "macro" "name")
"MY-MACRO-NAME"
CL-USER 34 > (intern (format nil "~:@(~a-~a-~a~)" "my" "macro" "name"))
MY-MACRO-NAME
edited Nov 24 '18 at 9:41
answered Nov 24 '18 at 9:34
Rainer JoswigRainer Joswig
112k8169290
112k8169290
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53453935%2fcommon-lisp-add-suffix-to-symbol-for-use-in-macros%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown