Common Lisp Programmatic Keyword
Asked Answered
Z

6

27

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

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

Zymase answered 17/10, 2008 at 10:54 Comment(1)
alexandria has a make-keyword functionRy
L
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")))
Larimore answered 17/10, 2008 at 11:31 Comment(3)
Almost, but not quite. When you create a keyword, you must also ensure that you set its value binding to itself.Spraggins
@Spraggins 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.Larimore
@Spraggins 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."Telesis
O
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")))
Openfaced answered 17/2, 2009 at 8:52 Comment(1)
It could be, of course, that OP just had print-case set to :downcaseTelesis
L
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")))
Larimore answered 17/10, 2008 at 11:31 Comment(3)
Almost, but not quite. When you create a keyword, you must also ensure that you set its value binding to itself.Spraggins
@Spraggins 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.Larimore
@Spraggins 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."Telesis
C
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.

Carmine answered 25/8, 2012 at 1:3 Comment(1)
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.)Telesis
L
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)))
Lyrist answered 5/4, 2019 at 0:45 Comment(1)
Can't you just do (read-from-string (concatenate 'string ":" name))?Gosplan
C
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)))
Corinthian answered 27/3, 2013 at 11:47 Comment(1)
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.Telesis
B
-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.

Brandish answered 17/10, 2008 at 11:22 Comment(3)
The name needs to be interned in the "KEYWORD" package to be a keyword. e.g., (intern "FOO" "KEYWORD")Larimore
ah yes. The (intern "foo" "KEYWORD") works quite nicely. Thank you.Zymase
In my answer, I've packaged it up into a neat little function, which you may enjoy. :-)Larimore

© 2022 - 2024 — McMap. All rights reserved.