Clojure: determine if a function exists - clojure

how can i know if a function name provided as string is callable or not in the current context? something like:
(callable? "asdasd") ;; false
(callable? "filter") ;; true
thanks

You are looking for resolve,
(resolve (symbol "asd"))
returns nil
(resolve (symbol "filter"))
return #'clojure.core/filter
To check if a var is a function (credit goes to #amalloy):
(-> s symbol resolve deref ifn?)

Chances are if you need this, you're doing something wrong, but...
(defn callable?
[s]
(let [obj (try (eval (symbol s)) (catch Exception e))]
(and obj (fn? obj))))

(defn callable? [name]
(clojure.test/function? (symbol name)))
UPD. I found out that fn? checks only for interface Fn and doesn't work for resolved symbol. Though, clojure.test/function? does what is needed, so I updated an example.

Related

Clojure: issues getting the symbol of a function in a looping context

Let's take that Clojure code:
(defn ^{:test-1 "meta-test-1"} fn-key-1
[x]
(eval nil))
(defn ^{:test-2 "meta-test-2"} fn-key-2
[x]
(eval nil))
(def some-map {fn-key-1 "test-1"
fn-key-2 "test-2"})
As you can see, the keys of my map are Symbols that refers to functions. I don't thing there is anything special there.
As you can see, when defining the map the keys of my map are Symbols that refers to functions. However, when they are read by the reader, then they get resolved to the function objects.
Now, what I want to do is to iterate over my some-map map to get the meta-data for each of the keys.
I was thinking doing this that way:
(defn some-fn
[m]
(doseq [[fn-key value] m]
(println (meta fn-key))))
However, what is being printed here is nil. This is expected since the meta-data is defining the symbol, and not the function. So, there is no meta-data attached to the function and it is why nil is being returned/printed.
So this lead to a question: is it possible to get the symbol that refers to my function "fn-key" in that context?
In that doseq loop, it appears that fn-key is a function and not the symbol of that function. What I need is a way to get the symbol of that function such that I can use (meta (get-symbol fn-key)).
Question Resolution
This question got resolved by defining the functions that way:
(def fn-key-1
(with-meta (fn [x] (eval nil)) {:foo "bar"}))
(def fn-key-2
(with-meta (fn [x] (eval nil)) {:foo "bar"}))
Revision of the Resolution
I revised the solution above to make it cleaner. In fact, if you were to type fn-key-1 in the REPL, you were to get an anonymous function reference such as #< clojure.lang.AFunction$1#15ab1764>. The problem with that is that it make things difficult to debug when you don't know what is being evaluated. To solve this issue, I changed the two function definitions to use this syntax, which resolve this issue:
(def fn-key-1 ^{:foo "bar"} (fn [x] (eval nil)))
(def fn-key-2 ^{:foo "bar"} (fn [x] (eval nil)))
Now, if we type fn-key-1 then we will get something like #<core$foo user.core$foo#66e37466> instead. At least, we have the namespace & symbol signature of this function object.
(def some-map {#'fn-key-1 "test-1"
#'fn-key-2 "test 2"})
fn-key-1 is resolved by the reader to the function object (which has no metadata to query). #'fn-key-1 resolves to the var itself, and holds the metadata.

Can't recognize destructured map value names from function argument's inside a when-let

I get this Compilation Error saying : Invalid token: function-name
(defn execute-task-from-message
"Parses the message dictionary, gets the function-name and arguments-list
and applys the function on the arguments"
[{function-name: "function-name"
arguments-list: "arguments-list"} msg]
(when-let [task (ns-resolve
*ns*
(symbol
(str task-namespace function-name)))]
(apply task arguments-list)))
What's going wrong with my code ?
some extra :s in your argument destructuring pehaps? If you include a bit of the stack trace and a bit more context I may be able to be more specific:
user> (def task-namespace "where-does-this-come-from")
#'user/task-namespace
user> (defn execute-task-from-message
"Parses the message dictionary, gets the function-name and arguments-list
and applys the function on the arguments"
[{function-name "function-name"
arguments-list "arguments-list"} msg]
(when-let [task (ns-resolve *ns*
(symbol
(str task-namespace function-name)))]
(apply task arguments-list)))
#'user/execute-task-from-message

How to call the same method in several Clojure namespaces?

I have a seq of namespace symbols:
(def namespace-symbols (namespace-1 namespace-2 namespace-3))
and I want to call the exact same method (say, run) over each one.
(map #{%/run} namespace-symbols)
won't work.
I also tried
(defmacro namespace-run
[namespace]
`(~(identity namespace)/run))
which also doesn't work. Is there any way to do this?
Update:
I finally came up with a macro like this:
(defmacro namespace-run
[namespace]
`(~(symbol (str namespace "/run"))))
(macroexpand-1 '(namespace-run foobar))
;=> (foobar/run)
Surely there is a better way to do this?
Check out clojure.core/ns-resolve
(doseq [ns namespace-symbols]
((ns-resolve ns 'run))) ;; resolve and execute fn
You can treat it just like a fn
(let [p (ns-resolve *ns* 'println)]
(p "Hello")
(p "World"))
Maybe use someting like symbol
clojure.core/symbol
([name] [ns name])
Returns a Symbol with the given namespace and name.

get a clojure function's code

Is there a way in clojure to get a function's code after the function has been loaded?
Ie. without doing something like [untested]
(defmacro blat [x] `(do (def code ~(quote (mexpand-all x)))
~x)))
(blat (defn func [abc] (...)))
You can get the source of a symbol using the clojure.repl/source function. However, this only works if the var for which the symbol resolves to is in a .clj file on the classpath. You can't, for example, do this:
user=> (defn foo [x] x)
#'user/foo
user=> (require 'clojure.repl)
nil
user=> (clojure.repl/source foo)
Source not found
nil

Dynamic method calls in a Clojure macro?

I'm attempting to write a macro which will call java setter methods based on the arguments given to it.
So, for example:
(my-macro login-as-fred {"Username" "fred" "Password" "wilma"})
might expand to something like the following:
(doto (new MyClass)
(.setUsername "fred")
(.setPassword "wilma"))
How would you recommend tackling this?
Specifically, I'm having trouble working out the best way to construct the setter method name and have it interpreted it as a symbol by the macro.
The nice thing about macros is you don't actually have to dig into the classes or anything like that. You just have to write code that generates the proper s-expressions.
First a function to generate an s-expression like (.setName 42)
(defn make-call [name val]
(list (symbol (str ".set" name) val)))
then a macro to generate the expressions and plug (~#) them into a doto expression.
(defmacro map-set [class things]
`(doto ~class ~#(map make-call things))
Because it's a macro it never has to know what class the thing it's being called on is or even that the class on which it will be used exists.
Please don't construct s-expressions with list for macros. This will seriously hurt the hygiene of the macro. It is very easy to make a mistake, which is hard to track down. Please use always syntax-quote! Although, this is not a problem in this case, it's good to get into the habit of using only syntax-quote!
Depending on the source of your map, you might also consider to use keywords as keys to make it look more clojure-like. Here is my take:
(defmacro configure
[object options]
`(doto ~object
~#(map (fn [[property value]]
(let [property (name property)
setter (str ".set"
(.toUpperCase (subs property 0 1))
(subs property 1))]
`(~(symbol setter) ~value)))
options)))
This can then be used as:
user=> (macroexpand-1 '(configure (MyClass.) {:username "fred" :password "wilma"}))
(clojure.core/doto (MyClass.) (.setUsername "fred") (.setPassword "wilma"))
Someone (I believe Arthur Ulfeldt) had an answer posted that was almost correct, but it's been deleted now.
This is a working version:
(defmacro set-all [obj m]
`(doto ~obj ~#(map (fn [[k v]]
(list (symbol (str ".set" k)) v))
m)))
user> (macroexpand-1 '(set-all (java.util.Date.) {"Month" 0 "Date" 1 "Year" 2009}))
(clojure.core/doto (java.util.Date.) (.setMonth 0) (.setDate 1) (.setYear 2009))
user> (set-all (java.util.Date.) {"Month" 0 "Date" 1 "Year" 2009})
#<Date Fri Jan 01 14:15:51 PST 3909>
You have to bite the bullet and use clojure.lang.Reflector/invokeInstanceMethod like this:
(defn do-stuff [obj m]
(doseq [[k v] m]
(let [method-name (str "set" k)]
(clojure.lang.Reflector/invokeInstanceMethod
obj
method-name
(into-array Object [v]))))
obj)
(do-stuff (java.util.Date.) {"Month" 2}) ; use it
No need for a macro (as far as I know, a macro would not allow to circumvent reflection, either; at least for the general case).