How to defn a function from string in Clojure?
Asked Answered
S

4

15

I'd like to do this (in REPL or anywhere)

(defn (symbol "print-string") [k] (println k))

and then be able to do

(print-string "lol")

Or, if there is any other way to create defn from custom strings in macroses, could you push me into the right direction please?

Smukler answered 24/3, 2009 at 19:24 Comment(0)
G
22
(defmacro defn-with-str [string args & body]
 `(defn ~(symbol string) ~args ~@body))

(defn-with-str "print-string" [k] (println k))

(print-string "lol")
Gandhi answered 24/3, 2009 at 21:40 Comment(4)
1. what is the ~ in front of args ? 2. what is the ~@ in front of body ?Ventre
@Ventre 1. ~ = unquote 2.~@ = expand sequenceCrosshatch
why is it that if I do (defn defns [] (doall (map (fn [s] (defn-with-str s [k] (println k))) ["print-string"]))) I get a fn called 's' ?Resemblance
@Resemblance macros aren't regular functionsGandhi
P
17

dnolen's solution works at macro expansion time, Brian Carper's at read-time. Now, here's one for run-time:

(intern *ns* (symbol "a") (fn [k] (println k)))
Plumcot answered 24/3, 2009 at 23:3 Comment(1)
Cool did not know about that. One caveat is that the var a will be missing the function metadata that you get from using defn.Gandhi
C
14

I like dnolen's answer better, but you can do this too:

(defn #=(symbol "print-string") [k] (println k))

#=() is evaluated at read-time. I don't know how stable a feature of Clojure this is, I wouldn't rely on it not to change in the future. Macros are how I'd do it.

Carr answered 24/3, 2009 at 21:59 Comment(0)
S
7

FYI - dnolen's answer will only work for literal strings, and not for strings in def'd or let'd variables.

(defmacro defn-with-str [string args & body] `(defn ~(symbol string) ~args ~@body))

(def hisym "hi") (defn-with-str hisym [] (println "hi"))

You now have a function called "hisym"

(hi) -> java.lang.Exception: Unable to resolve symbol: hi in this context (NO_SOURCE_FILE:6) (hisym) -> prints "hi"

To avoid this, eval the function name string in the macro

(defmacro defn-with-str [string args & body]
`(defn ~(symbol (eval string)) ~args ~@body))

Seften answered 10/3, 2010 at 0:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.