While I may incorrectly interpret the concept of homoiconicity, I've understood it as 'code being data'.
So, I can write code like this:
(def subject "world")
(def helo '(str "Hello " subject))
At this point, helo
is only data, but can be executed as code like this:
(eval helo)
which returns "Hello world".
I can also continue to treat helo
as data:
(first helo)
(count helo)
which returns respectively str
and 3
.
So far so good. However, as soon as I wrap the code in a function, I seem to lose the ability to treat code as data:
(defn helofn [subject]
(str "Hello " subject))
How do I decompose helofn
? It seems that I can't treat it as data; if I do this:
(count helofn)
I get an exception:
java.lang.UnsupportedOperationException: count not supported on this type: user$helofn
Is there another way to decompose helofn
, or am I just expecting too much from homoiconicity?
defn
is just a macro:If you define
helofn
the way you definedhelo
, you'll be able to treat it as data:Now you can eval and call this function:
and to treat it as a data:
But, when you use
defn
macro you associateshelofn
variable with compiled function and not with it's code.It's not just functions. Let's say you defined
hello
with the following code:Now
hello
is associated with "Hello world" string and not with(str "Hello " subject)
code. So, now there is no way to get the code this string was built with.N.B. If you want to treat clojure code as data you should look into its macros. Any code passed to a macro is treated as data and any data returned by a macro is treated as code.