Symbol to keyword

64 views
Skip to first unread message

Dragan Djuric

unread,
Aug 24, 2009, 12:31:57 PM8/24/09
to Clojure
Hi,

I needed (and created) a macro to generate keywords from symbols. I
couldn't find anything ready, and I am still not completely
comfortable with the solution I came up with. Any suggestions for
improvement?

Here is what it should do:
=> (def name1 "A")
=> (to-keyword name1)
:user/name1
=> (ns namespace2)
=> (def name2 "b")
=> (ns user)
=> (use namespace2)
=> (to-keyword name2)
:namespace2/name2

And the code:

(defmacro to-keyword
[sym]
`(keyword (second (re-find #"#'(.*?)/" (str (resolve '~sym)))) (name
'~sym)))

I feel that the least that could be done is that the regex could be
improved (I don't know regexes almost at all)...

Konrad Hinsen

unread,
Aug 24, 2009, 1:07:34 PM8/24/09
to clo...@googlegroups.com
On 24 Aug 2009, at 18:31, Dragan Djuric wrote:

> I needed (and created) a macro to generate keywords from symbols. I
> couldn't find anything ready, and I am still not completely
> comfortable with the solution I came up with. Any suggestions for
> improvement?

What are your exact requirements? Here's the most straightforward
solution:

(keyword 'abc)
:abc

(keyword 'x/y)
:x/y

But apparently you want to convert a non-qualified symbol to a
namespace-qualified keyword. Is that right?

Konrad.

Dragan Djuric

unread,
Aug 24, 2009, 1:55:51 PM8/24/09
to Clojure
Yes. The trick is that
(keyword 'x/y)
is different from
(ns x)
::y

Laurent PETIT

unread,
Aug 24, 2009, 2:03:24 PM8/24/09
to clo...@googlegroups.com


2009/8/24 Dragan Djuric <drag...@gmail.com>


Yes. The trick is that
(keyword 'x/y)
is different from
(ns x)
::y

??

Achim Passen

unread,
Aug 24, 2009, 2:38:17 PM8/24/09
to clo...@googlegroups.com
Hi!

Am 24.08.2009 um 18:31 schrieb Dragan Djuric:

> I needed (and created) a macro to generate keywords from symbols. I
> couldn't find anything ready, and I am still not completely
> comfortable with the solution I came up with. Any suggestions for
> improvement?

If I understand you correctly, you'd like to convert symbols which
name vars to keywords qualified with the namespace which contains the
var's definition. You don't really need a macro for that, a regular
function will do. Here's a version using var metadata:

(defn resolve-to-kw [sym]
(let [md (meta (resolve sym))]
(keyword (-> md :ns ns-name name) (-> md :name name))))

Hope this helps.

Kind Regards,
Achim

Meikel Brandmeyer

unread,
Aug 24, 2009, 2:40:00 PM8/24/09
to clo...@googlegroups.com
Hi,

Am 24.08.2009 um 20:03 schrieb Laurent PETIT:

>> Yes. The trick is that
>> (keyword 'x/y)
>> is different from
>> (ns x)
>> ::y
>
> ??

::y is similar to `y. (Besides the resolving issue, which doesn't make
sense for keywords...)

For keyword there was some issue, that (keyword "foo/bar") creates a
keyword with "name" foo/bar and "namespace" "", while (ns foo) ::bar,
makes a keyword with namespace "foo" and name "bar".

Sincerely
Meikel

Konrad Hinsen

unread,
Aug 24, 2009, 2:51:53 PM8/24/09
to clo...@googlegroups.com
On 24 Aug 2009, at 19:55, Dragan Djuric wrote:

> Yes. The trick is that
> (keyword 'x/y)
> is different from
> (ns x)
> ::y

Not in my copy of Clojure:

user=> (ns x)
nil
x=> ::y
:x/y
x=> (identical? ::y (keyword 'x/y))
true

Konrad.


Meikel Brandmeyer

unread,
Aug 25, 2009, 5:27:55 AM8/25/09
to Clojure
Hi,

On Aug 24, 8:51 pm, Konrad Hinsen <konrad.hin...@fastmail.net> wrote:

> > Yes. The trick is that
> > (keyword 'x/y)
> > is different from
> > (ns x)
> > ::y
>
> Not in my copy of Clojure:
>
> user=> (ns x)
> nil
> x=> ::y
> :x/y
> x=> (identical? ::y (keyword 'x/y))
> true

This does not work in Clojure 1.0. As well as (keyword 'x/y) throws an
exception there.

Clojure
1:1 user=> (keyword 'x/y)
java.lang.ClassCastException: clojure.lang.Symbol (repl-1:1)
1:2 user=> (identical? ::y (keyword "user/y"))
false

Sincerely
Meikel

Dragan Djuric

unread,
Aug 25, 2009, 6:47:26 AM8/25/09
to Clojure
I needed a macro if I wanted to avoid ' in calls. It may seem as
nitpicking but (to-keyword name) is more readable and less error prone
than (to-keyword 'name) if I need to use it in lots of places.

Dragan Djuric

unread,
Aug 25, 2009, 7:37:30 AM8/25/09
to Clojure
And the problem with the plain (keyword x) approach is how the
namespace resolving works in that case. I can see that some things
have been improved in Clojure 1.1 compared to 1.0, but there is still
one thing:

In 1.1. if I call (keyword 'foo/bar) i'll get :foo/bar. OK, because
the namespace is explicitly mentioned in the call.
But, if I want to create keyword from any var imported from another
namespace, using a macro to create a symbol:
(defmacro [sym] `(keyword '~sym))
(ns foo)
(def bar "A")
(ns user)
(use foo)
(to-keyword bar) ;; note that bar is actually the foo/bar
:bar ;;it should be :foo/bar!

Jarkko Oranen

unread,
Aug 25, 2009, 8:27:16 AM8/25/09
to Clojure

On Aug 25, 1:47 pm, Dragan Djuric <draga...@gmail.com> wrote:
> I needed a macro if I wanted to avoid ' in calls. It may seem as
> nitpicking but (to-keyword name) is more readable and less error prone
> than (to-keyword 'name) if I need to  use it in lots of places.

If that's all you do, then the easiest approach is to write both the
function and the macro.

Assume you have the function version, called to-keyword* ("foo*" is a
naming convention for something that is a "variant of foo"), then the
macro is as easy as:

(defmacro to-keyword [sym]
`(to-keyword* ~sym))

the driver function idiom is very common and useful, as writing
functions is much less error prone than writing macros. This approach
also has the advantage that if you ever need to transform a collection
of symbols, all you need to do is map the to-keyword* function.

--
Jarkko
Reply all
Reply to author
Forward
0 new messages