Suppose I define x as symbol function foo
(defn foo [x] x)
(def x foo)
Can the name "foo" be discovered if only given x?
Is there a way within foo to look up the name of the function x - "foo" in this case?
(foo x)
Is there or is it possible to create a function such as:
(get-fn-name x)
foo
A similar question was asked recently on this site; see here
When you do
(def x foo)
, you are defining x to be "the value atfoo
", not "foo
itself". Oncefoo
has resolved to its value, that value no longer has any relationship whatsoever tofoo
.So maybe you see one possible answer to your question now: don't resolve
foo
when you go to do definex
. Instead of doing......do...
Now if you try to get the value of
x
, you will getfoo
(literally), not the value thatfoo
resolves to.However, that is likely problematic, because you will probably also sometimes want to be able to get at the value that
foo
resolves to usingx
. However however, you would be able to do this by doing:If I were to describe what this does it would be: "get the value
x
resolves to, use that as a symbol, then resolve that symbol to its var (not its value), and dereference that var to obtain a value"....Now let's do something hacky. I'm not sure I would advise doing either of these things I'm about to suggest, but you did ask
Can the name "foo" be discovered if only given x?
, and I can think of two ways you could do that.Method #1: regex the fn var name
Notice what
foo
andx
both resolve to below:Now, check this out:
Cool. This only works because
foo
resolves to a function, which happens to have a var-like name, a name which will be the same forx
because it refers to the same function. Note that "foo" is contained within the string produced by(str x)
(and also by(foo x)
). This is because the function's var name is apparently created with some backwards reference to the symbol that was used to initially define it. We're going to use this fact to find that very symbol from any function.So, I wrote a regular expression to find "foo" inside that string of the function var name. It isn't that it looks for "foo", but rather that it looks for any sub-string--in regex terms,
".*"
--that is preceded by a\$
character--in regex terms"(?<=\$)"
--and followed by the\@
character--in regex terms"(?=@)"
...We can further convert this to a symbol by simply wrapping
(symbol ...)
around it:Furthermore, this whole process could be generalized to a function that will take a function and return the symbol associated with that function's var name--which is the symbol was given when the function was initially defined (this process will not at all work nicely for anonymous functions).
...or this which I find nicer to read...
Now we can do...
Method #2: reverse lookup all ns mappings based on identity
This is going to be fun.
So, we're going to take all the namespace mappings, then
dissoc
'x
from it, then filter what remains based on whether the val at each mapping refers to the exact same thing as whatx
resolves to. We'll take the first thing in that filtered sequence, and then we'll take the key at that first thing in order to get the symbol.Notice that if you replaced
x
withfoo
above, you would getx
. Really all this is doing is returning the first name it finds that maps to the exact same value asx
. As before, this could be generalized to a function:The main difference here is that the argument will have to be a quoted symbol.
This
find-equiv-sym
function is really not very good. Problems will happen when you have multiple things in the namespace resolving to identical values. You could return this list of symbols that resolve to identical things (instead of just returning the first one), and then process it further from there. It would be simple to change the current function to make this work: delete the last two lines (first
andkey
), and replace them with(map key)
.Anyways, I hope this was as fun and interesting for you as it was for me, but I doubt whether either of these hacks would be a good way of going about things. I advocate my first solution.
It's not clear why you would want to do this - when you do
(def x foo)
you are effectively giving the namex
to a new var in your namespace. It happens to have the same value asfoo
(i.e. it contains the same function) but is otherwise completely independent from foo. It's like having two references to the same object, to use a Java analogy.Why should you continue to want to obtain the name
foo
?If you really want to do something similar to this, this might be a case where you could use some custom metadata on the function which contains the original symbol: