Using a function to def other functions?

135 views
Skip to first unread message

fah...@gmail.com

unread,
Aug 8, 2016, 2:52:37 PM8/8/16
to Clojure
user> (macroexpand-1 '(defn foo [x] (inc x)))
(def foo (clojure.core/fn ([x] (inc x))))

If defn is just a macro, then it seems I can do this:

user> (defn bar [] (fn ([x] (inc x))))
#'user/bar

user
> (def foo (bar))
#'user/foo

user
> foo
#function[user/bar/fn--10778]

But the result is a little different than doing it directly with defn:

user> (defn foo [x] (inc x))
#'user/foo

We had #'user/bar/fn--10778 vs #'user/foo. But either way, foo is bound to something.

Is the difference significant? It seems like it is because I tried something similar in my project and got the following:

IllegalStateException Attempting to call unbound fn: #'p.core/default-step  clojure.lang.Var$Unbound.throwArity (Var.java:43)
p
.core> default-step
#function[p.core/make-step/fn--10747]

Function default-step was def'd using make-step which returned a function and default-step is bound, so why does the repl say it is not?

(defn make-step [some-args]
 
(fn ([other-args]
       
(some-body using-both-args))))

Basically I need to define a bunch of similar functions and am trying to use another function to help define them (instead of using a macro). But it seems I'm doing something wrong...

adrian...@mail.yu.edu

unread,
Aug 8, 2016, 4:14:34 PM8/8/16
to Clojure
Using defining macros as non top-level forms may not be forbidden by the language but its use is generally discouraged. See http://clhs.lisp.se/Issues/iss104_w.htm for a discussion about this issue in Common Lisp for some background context. In short, compile time effects may not be captured whenever you use defining macros as non top-level forms. I think you're seeing something like this manifest here. In this case, since you referenced a var which was not installed when the compiler reaches the calling code, the compiler will throw this error message. I would suggest rethinking this because the solution is ugly, but you should use something like clojure.core/resolve or clojure.core/ns-resolve to resolve the var dynamically and then funcall it. 

fah...@gmail.com

unread,
Aug 8, 2016, 5:19:04 PM8/8/16
to Clojure
Oh...   'bar' and 'make-step' count as macros? My intent was that they're ordinary functions that return functions. Am I mistaken? Or does the issue you referred to apply to using defining functions and macros as non-top-level forms?

(defn bar [] (fn ([x] (inc x))))

adrian...@mail.yu.edu

unread,
Aug 8, 2016, 5:30:12 PM8/8/16
to Clojure
defn, def, etc are what I mean by "defining macros". 

adrian...@mail.yu.edu

unread,
Aug 8, 2016, 5:31:05 PM8/8/16
to Clojure
def isn't a good example actually because it's a special form. But the same principle applies when using it as a non-top level form. 

Gregg Reynolds

unread,
Aug 8, 2016, 5:33:34 PM8/8/16
to clo...@googlegroups.com

Use the source, Luke!

Spend some quality time with the source code of deftype, defrecord, ns, etc. and you will not regret it.  Monkey with the ns- functions to explore namespaces, interning, etc.  Make sure you grok the relation between vars and values. Once you get the hang of how Clojure does it you'll find it easy to roll your own.

You will almost certainly want to use some macros, but what's wrong with that?

gregg

Message has been deleted

fah...@gmail.com

unread,
Aug 8, 2016, 7:16:03 PM8/8/16
to Clojure
Ah, are you saying the binding isn't taking place at the top level because I had to call 'bar' to get the right hand side (so to speak) of the binding?

And if 'bar' were a macro instead, then it would be expanded first and then nothing would have to be evaluated before binding to 'foo', and so it would be at the top level?


Reply all
Reply to author
Forward
0 new messages