0

I'm trying to create a Clojure function, that returns another function with a custom name. My attempts so far:

(defn function-with-custom-name [name] (fn name [] 42))
(function-with-custom-name "hello")
# --> #object[lang.main$function_with_custom_name$name__4660 0xa6afefa "lang.main$function_with_custom_name$name__4660@a6afefa"]
# syntactically ok, but its name is 'name' and not 'hello'

(defn function-with-custom-name [name] (fn (symbol name) [] 42))
# --> CompilerException java.lang.IllegalArgumentException: Parameter declaration symbol should be a vector, compiling:(/tmp/form-init3365336074265515078.clj:1:40)

(defn function-with-custom-name [name] (fn '(symbol name) [] 42))
# --> CompilerException java.lang.IllegalArgumentException: Parameter declaration quote should be a vector, compiling:(/tmp/form-init3365336074265515078.clj:1:40)

I understand that fn is a macro, and therefore proper quoting is probably important for the parameter, but as per above, I could not get it right, but I'm 99% sure there is a way, since (looking at the source of fn), the only criteria is that the first parameter should be recognized as a symbol.

Any hints on how to do this?

EDIT: Use-case, as asked in the comment: I'm writing a simple language interpreter in Clojure, which (among other things) lets you create functions. The functions from my language are currently represented by anonymous Clojure functions. However, it would make debugging the interpreter much easier, if the Clojure functions also did have a name.

EDIT2: The first edit made me think, and I came to the conclusion that I cannot use macro-based solutions for this problem, since I need to create the functions run-time (and, as far as I remember, macros can only work at compile-time). --> Changed the question title for clarity. Still, please don't delete the macro-based answers, since they give helpful insight.

2
  • Can you clarify the use-case for this (i.e. why you are creating the fn at runtime and how it will be used)? Commented Nov 2, 2017 at 18:14
  • @AlanThompson: see edit. Commented Nov 2, 2017 at 20:39

3 Answers 3

1

You can use defmacro.

(defmacro function-with-custom-name [name] 
  `(fn ~(symbol name) ([] 42)))
Sign up to request clarification or add additional context in comments.

Comments

1

you can also do it in runtime, without using macros, using namespace functions instead. It can give you the way to register functions from some input for example (i can't really find any good reason for this though, but maybe it's just me)

user> (defn runtime-defn [f-name f]
        (intern (ns-name *ns*) (symbol f-name) f))
#'user/runtime-defn

user> (runtime-defn "my-fun" #(* 100 %))
#'user/my-fun

user> (my-fun 123)
;;=> 12300

user> (runtime-defn (read) #(* 200 %))
#input "danger!!!"

#'user/danger!!!

user> (danger!!! 1)
;;=> 200

Comments

0

Update:

For the simple version, you can use defmacro. For a more complicated version (such as used by the potemkin library) you need to mess around with creating a var and "intern-ing" it into the clojure namespace. This is accomplished via clojure.core/intern:

(ns tst.demo.core
  (:use demo.core tupelo.test )
  (:require [tupelo.core :as t] ))
(t/refer-tupelo)

(defmacro  make-fn-macro-unquote [name]
  (spyxx name)
  `(defn ~name [] 42))

(defn  make-fn-func-quote [name2]
  (spyxx name2)
  (intern 'tst.demo.core (symbol name2) (fn [] 43)))

(dotest
  (make-fn-macro-unquote fred)
  (spyxx fred)
  (is= 42 (spyx (fred)))

  (let [wilma-var (make-fn-func-quote "wilma")]
    (spyxx wilma-var)
    (is= 43 (spyx (wilma-var)))))

Look at the output:

name => clojure.lang.Symbol->fred
fred => tst.demo.core$fn__38817$fred__38818->#object[tst.demo.core$fn__38817$fred__38818 0x5f832a1 "tst.demo.core$fn__38817$fred__38818@5f832a1"]
(fred) => 42

name2 => java.lang.String->"wilma"
wilma-var => clojure.lang.Var->#'tst.demo.core/wilma
(wilma-var) => 43

Note that fred is a clojure function, while wilma-var is a clojure var. Please see this post on the relationship between a symbol like foo and a var and a function.

Note also that the macro version takes an unquoted symbol fred as input, while the function version takes a plain string in double-quotes as input.

So fred is a symbol pointing to a function, while wilma-var is a symbol pointing to a var (which then points to a function). In either case, Clojure allows us to type (fred) or (wilma-var) to make a function call, and we get either 42 or 43 as a result.

3 Comments

What are dotest and is=?
Thanks, I tried your solution, and it worked fine. Would you mind explaining why it does not work with function call?
@Downvoter: can you please explain what was wrong with this answer? Was there something factually incorrect? (Upvoted for explaining the background, even though I admit I don't yet fully understand it ;) )

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.