27

Is there a function in Common Lisp that takes a string as an argument and returns a keyword?

Example: (keyword "foo") -> :foo

1
  • alexandria has a make-keyword function Commented Aug 14, 2023 at 9:59

6 Answers 6

44

The answers given while being roughly correct do not produce a correct solution to the question's example.

Consider:

CL-USER(4): (intern "foo" :keyword)

:|foo|
NIL
CL-USER(5): (eq * :foo)

NIL

Usually you want to apply STRING-UPCASE to the string before interning it, thus:

(defun make-keyword (name) (values (intern (string-upcase name) "KEYWORD")))
Sign up to request clarification or add additional context in comments.

1 Comment

It could be, of course, that OP just had print-case set to :downcase
35

Here's a make-keyword function which packages up keyword creation process (interning of a name into the KEYWORD package). :-)

(defun make-keyword (name) (values (intern name "KEYWORD")))

3 Comments

Almost, but not quite. When you create a keyword, you must also ensure that you set its value binding to itself.
@Vatine I only have SBCL to test, and in SBCL, (symbol-value (intern "FOO" "KEYWORD")) already has the correct value. Besides, Alexandria implements it using the same approach also.
@Vatine 11.1.2.3.1 Interning a Symbol in the KEYWORD Package says (emphasis added), "The KEYWORD package is treated differently than other packages in that special actions are taken when a symbol is interned in it. In particular, when a symbol is interned in the KEYWORD package, it is automatically made to be an external symbol and is automatically made to be a constant variable with itself as a value."
3

There is a make-keyword function in the Alexandria library, although it does preserve case so to get exactly what you want you'll have to upcase the string first.

1 Comment

Or set print-case to :downcase. intern doesn't do any case modification, so the solution here probably shouldn't either. (Although the example in the question does say (keyword "foo") => :foo, it's probably better to have (... "foo") => :|foo| or (... "FOO") => :FOO.)
2

In case, you can change the string to start with colon sign :

use read-from-string directly.

Here is another version of make-keyword:

(defun make-keyword (name)
           (read-from-string (concatenate 'string ":" name)))

1 Comment

Can't you just do (read-from-string (concatenate 'string ":" name))?
1

In this example it also deals with strings with spaces (replacing them by dots):

(defun make-keyword (name) (values (intern (substitute #\. #\space (string-upcase name)) :keyword)))

1 Comment

Is there a reason that you'd want to replace spaces with dots? If you intern "foo bar" you get a symbol with the name "foo bar", and there's no problem with that. intern doesn't replace spaces with dots, either.
-5
(intern "foo" "KEYWORD") -> :foo

See the Strings section of the Common Lisp Cookbook for other string/symbol conversions and a detailed discussion of symbols and packages.

3 Comments

The name needs to be interned in the "KEYWORD" package to be a keyword. e.g., (intern "FOO" "KEYWORD")
ah yes. The (intern "foo" "KEYWORD") works quite nicely. Thank you.
In my answer, I've packaged it up into a neat little function, which you may enjoy. :-)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.