In a Clojure exercise that I'm working on, I have several multimethods, all of which just use identity as the dispatch function. For example:
(defmulti amount identity)
(defmulti bottles identity)
(defmulti pronoun identity)
(defmulti action identity)
(defmulti pred identity)
Since all of them use the same identity function for dispatch, I would like to just iterate over the names and call defmulti for each name instead of repeating the defmulti calls. I tried this:
(doseq [m '(amount bottles pronoun action pred)]
(defmulti m identity))
However, when I do that it seems as though the defmulti does not have the proper effect, as when I later use defmethod for any of multimethod names, I get an error such as:
(defmethod amount 0 [n] "whatever")
CompilerException java.lang.RuntimeException: Unable to resolve symbol: amount in this context, compiling:(NO_SOURCE_PATH:1:1)
Is it possible to iterate over a list of symbols or names and call defmulti for each of them, and if so how can it be done?
You can create a macro that wraps over defmulti and does the required thing:
(defmacro defidmulti [names]
`(do ~#(for [m names]
`(defmulti ~m identity))))
(defidmulti [amount bottles pronoun action pred])
Related
My goal is a function/macro that works like this:
(def f (polymorphic-fn
java.lang.Long (fn [a] (inc a))
java.lang.String (fn [a] (str a "x"))))
(f 1) ;; => 2
(f "abc") ;; => "abcx"
Since the type-based dispatch of protocols has the best performance I was thinking to create an 'anonymous' protocol for the 'fused' function with a macro like this:
(defmacro polymorphic-fn
[& pairs]
(let [proto (gensym)
method (gensym)
extends (for [[type handler] pairs]
`(extend ~type ~proto {(keyword ~method) ~handler}))]
`(do
(defprotocol ~proto (~method [e#]))
~#extends
~method)))
This produces the error: Unable to resolve symbol: G__18707.
Is there a way to return the 'anonymous' method, or is there a better way to implement such a function?
The problem is that the defprotocol will generate code that will intern the protocol methods. Ie. after macroexpansion, the symbols for your defined method is still not known to the compiler. Thus, the compilation fails and will barf that the symbol is unknown.
Many other def...'s will generate a macro "call" that will intern the symbol during macro expansion (and thus the compiler will remain happy).
To fix it you can just declare it beforehand. This works since declare is macro, will get expanded and the compiler will be happy:
(defmacro polymorphic-fn
[& pairs]
(let [proto (gensym "proto")
method (gensym "prot-method-")
extends (for [[type handler] (partition 2 pairs)]
`(extend ~type ~proto {~(keyword (str method)) ~handler}))]
`(do
(declare ~method)
(defprotocol ~proto (~method [e#]))
~#extends
~method)))
Note: I also fixed the keyword call in this.
I think you just want to use regular protocols, along with extend-type:
(defprotocol Fooable
(foo [this]) )
(extend-type java.lang.Long
Fooable
(foo [some-long] (inc some-long)))
(extend-type java.lang.String
Fooable
(foo [any-string] (str any-string "-and-more")))
with result:
(foo 3) => 4
(foo "hello") => "hello-and-more"
It may be possible to use a macro to hide the protocol name by using an auto-gensym, but I don't see the point. Just ignore the protocol name 'Fooable' and you have the same result.
Also, be aware that parts of Clojure implementation create concrete Java classes behind the scenes, which may require a hard-coded name.
You could also mimic the protocol functionality by using a cond:
(defn bar [it]
(cond
(= (class it) java.lang.Long) (inc it)
(= (class it) java.lang.String) (str it "-and-more")))
(bar 7) => 8
(bar "farewell") => "farewell-and-more"
You could define a function to generate bar like you do with polymorphic-fn if you wanted.
In clojure, can one idiomatically obtain a function's name inside of its body, hopefully accomplishing so without introducing a new wrapper for the function's definition? can one also access the function's name inside of the body of the function's :test attribute as well?
For motivation, this can be helpful for certain logging situations, as well as for keeping the body of :test oblivious to changes to the name of the function which it is supplied for.
A short elucidation of the closest that meta gets follows; there's no this notion to supply to meta, as far as I know, in clojure.
(defn a [] (:name (meta (var a))))
Obviously it is easy to accomplish with a wrapper macro.
Edit: luckily no one so far mentioned lambda combinators.
There are 2 ways to approach your question. However, I suspect that to fully automate what you want to do, you would need to define your own custom defn replacement/wrapper.
The first thing to realize is that all functions are anonymous. When we type:
(defn hello [] (println "hi"))
we are really typing:
(def hello (fn [] (println "hi"))
we are creating a symbol hello that points to an anonymous var which in turn points to an anonymous function. However, we can give the function an "internal name" like so:
(def hello (fn fn-hello [] (println "hi")))
So now we can access the function from the outside via hello or from the inside using either hello of fn-hello symbols (please don't ever use hello in both locations or you create a lot of confusion...even though it is legal).
I frequently use the fn-hello method in (otherwise) anonymous functions since any exceptions thrown will include the fn-hello symbol which makes tracking down the source of the problem much easier (the line number of the error is often missing from the stack trace). For example when using Instaparse we need a map of anonymous transform functions like:
{
:identifier fn-identifier
:string fn-string
:integer (fn fn-integer [arg] [:integer (java.lang.Integer. arg)])
:boolean (fn fn-boolean [arg] [:boolean (java.lang.Boolean. arg)])
:namespace (fn fn-namespace [arg] [:namespace arg])
:prefix (fn fn-prefix [arg] [:prefix arg])
:organization (fn fn-organization [arg] [:organization arg])
:contact (fn fn-contact [arg] [:contact arg])
:description (fn fn-description [arg] [:description arg])
:presence (fn fn-presence [arg] [:presence arg])
:revision (fn fn-revision [& args] (prepend :revision args))
:iso-date (fn fn-iso-date [& args] [:iso-date (str/join args)])
:reference (fn fn-reference [arg] [:reference arg])
:identity (fn fn-identity [& args] (prepend :identity args))
:typedef (fn fn-typedef [& args] (prepend :typedef args))
:container (fn fn-container [& args] (prepend :container args))
:rpc (fn fn-rpc [& args] (prepend :rpc args))
:input (fn fn-input [& args] (prepend :input args))
...<snip>...
}
and giving each function the "internal name" makes debugging much, much easier. Perhaps this would be unnecessary if Clojure had better error messages, but that is a longstanding (& so far unfullfilled) wish.
You can find more details here: https://clojure.org/reference/special_forms#fn
If you read closely, it claims that (defn foo [x] ...) expands into
(def foo (fn foo [x] ...))
although you may need to experiment to see if this has already solved the use-case you are seeking. It works either way as seen in this example where we explicitly avoid the inner fn-fact name:
(def fact (fn [x] ; fn-fact omitted here
(if (zero? x)
1
(* x (fact (dec x))))))
(fact 4) => 24
This version also works:
(def fact (fn fn-fact [x]
(if (zero? x)
1
(* x (fn-fact (dec x))))))
(fact 4) => 24
(fn-fact 4) => Unable to resolve symbol: fn-fact
So we see that the "internal name" fn-fact is hidden inside the function and is invisible from the outside.
A 2nd approach, if using a macro, is to use the &form global data to access the line number from the source code. In the Tupelo library this technique is used to improve error messages for the
(defmacro dotest [& body] ; #todo README & tests
(let [test-name-sym (symbol (str "test-line-" (:line (meta &form))))]
`(clojure.test/deftest ~test-name-sym ~#body)))
This convenience macro allows the use of unit tests like:
(dotest
(is (= 3 (inc 2))))
which evalutes to
(deftest test-line-123 ; assuming this is on line 123 in source file
(is (= 3 (inc 2))))
instead of manually typing
(deftest t-addition
(is (= 3 (inc 2))))
You can access (:line (meta &form)) and other information in any macro which can make your error messages and/or Exceptions much more informative to the poor reader trying to debug a problem.
Besides the above macro wrapper example, another (more involved) example of the same technique can be seen in the Plumatic Schema library, where they wrap clojure.core/defn with an extended version.
You may also wish to view this question for clarification on how Clojure uses the "anonymous" var as an intermediary between a symbol and a function: When to use a Var instead of a function?
I am working through Clojure for the Brave and True. In the chapter on macros there is this exercise:
Write a macro that defines an arbitrary number of attribute-retrieving functions using one macro call. Here’s how you would call it:
(defattrs c-int :intelligence
c-str :strength
c-dex :dexterity)
What these functions do is retrieve a value from a map. For example given: (def character {:name "Travis", :intelligence 20, :strength 23, :dexterity 13})
The result of (c-int character) would be 20 of course such a function could easily be defined as (def c-int #(:intelligence %))
This is the solution I came up with to the problem:
(defmacro defattrs
[& attributes]
`(let [attribute-pairs# (partition 2 (quote ~attributes))]
(map (fn [[function-name# attribute-key#]]
(def function-name# #(attribute-key# %)))
attribute-pairs#)))
The problem I am having is that def uses the generated symbol name instead of what it resolves to to define the function (which in hindsight makes sense given the usage of def). My attempts to use expressions with defining functions such as:
(let [x ['c-int :intelligence]]
(def (first x) #((second x) %)))
Have resulted in this error: CompilerException java.lang.RuntimeException: First argument to def must be a Symbol, compiling:(/tmp/form-init5664727540242288850.clj:2:1)
Any ideas on how I can achieve this?
There are ordinary manipulations that you do with the attributes parameter that don't need to be generated as forms:
splitting the attributes into attribute-pairs; and
defining the function to generate a def form for each pair.
Applying the above to your code, we get ...
(defmacro defattrs [& attributes]
(let [attribute-pairs (partition 2 attributes)]
(map (fn [[function-name attribute-key]]
`(def ~function-name #(~attribute-key %)))
attribute-pairs)))
The scope of the back-quote is restricted to the def we wish to generate.
The values of the function-name and attribute-key parameters of the function are inserted into the def form.
There is one problem remaining.
The result of the map is a sequence of def forms.
The first one will be interpreted as a function to
apply to the rest.
The solution is to cons a do onto the front of the sequence:
(defmacro defattrs [& attributes]
(let [attribute-pairs (partition 2 attributes)]
(cons 'do
(map (fn [[function-name attribute-key]]
`(def ~function-name ~attribute-key))
attribute-pairs))))
I've also abbreviated #(~attribute-key %) to the equivalent ~attribute-key within the back-quoted form.
Let's see what the expansion looks like:
(macroexpand-1 '(defattrs dooby :brrr))
;(do (def dooby :brrr))
Looks good. Let's try it!
(defattrs gosh :brrr)
(gosh {:brrr 777})
;777
It works.
You have found the use-case for the back-quote and tilde. Just try this:
(let [x ['c-int :intelligence]]
(eval `(def ~(first x) #(~(second x) %))))
(def character {:name "Travis", :intelligence 20, :strength 23, :dexterity 13})
(c-int character) => 20
The back-quote is similar to the single-quote in that it makes the next form into a data structure of lists, symbols, etc. The difference is that the data structure is intended to be used as a template, where internal bits can be substituted using the tilde. The cool part is that the tilde doesn't just substitute items, but works for live code that can be any arbitrary Clojure expression.
First, I have no experience with CS and Clojure is my first language, so pardon if the following problem has a solution, that is immediately apparent for a programmer.
The summary of the question is as follows: one needs to create atoms at will with unknown yet symbols at unknown times. My approach revolves around a) storing temporarily the names of the atoms as strings in an atom itself; b) changing those strings to symbols with a function; c) using a function to add and create new atoms. The problem pertains to step "c": calling the function does not create new atoms, but using its body does create them.
All steps taken in the REPL are below (comments follow code blocks):
user=> (def atom-pool
#_=> (atom ["a1" "a2"]))
#'user/atom-pool
'atom-pool is the atom that stores intermediate to-be atoms as strings.
user=> (defn atom-symbols []
#_=> (mapv symbol (deref atom-pool)))
#'user/atom-symbols
user=> (defmacro populate-atoms []
#_=> (let [qs (vec (remove #(resolve %) (atom-symbols)))]
#_=> `(do ~#(for [s qs]
#_=> `(def ~s (atom #{}))))))
#'user/populate-atoms
'populate-atoms is the macro, that defines those atoms. Note, the purpose of (remove #(resolve %) (atom-symbols)) is to create only yet non-existing atoms. 'atom-symbols reads 'atom-pool and turns its content to symbols.
user=> (for [s ['a1 'a2 'a-new]]
#_=> (resolve s))
(nil nil nil)
Here it is confirmed that there are no 'a1', 'a2', 'a-new' atoms as of yet.
user=> (defn new-atom [a]
#_=> (do
#_=> (swap! atom-pool conj a)
#_=> (populate-atoms)))
#'user/new-atom
'new-atom is the function, that first adds new to-be atom as string to `atom-pool. Then 'populate-atoms creates all the atoms from 'atom-symbols function.
user=> (for [s ['a1 'a2 'a-new]]
#_=> (resolve s))
(#'user/a1 #'user/a2 nil)
Here we see that 'a1 'a2 were created as clojure.lang.Var$Unbound just by defining a function, why?
user=> (new-atom "a-new")
#'user/a2
user=> (for [s ['a1 'a2 'a-new]]
#_=> (resolve s))
(#'user/a1 #'user/a2 nil)
Calling (new-atom "a-new") did not create the 'a-new atom!
user=> (do
#_=> (swap! atom-pool conj "a-new")
#_=> (populate-atoms))
#'user/a-new
user=> (for [s ['a1 'a2 'a-new]]
#_=> (resolve s))
(#'user/a1 #'user/a2 #'user/a-new)
user=>
Here we see that resorting explicitly to 'new-atom's body did create the 'a-new atom. 'a-new is a type of clojure.lang.Atom, but 'a1 and 'a2 were skipped due to already being present in the namespace as clojure.lang.Var$Unbound.
Appreciate any help how to make it work!
EDIT: Note, this is an example. In my project the 'atom-pool is actually a collection of maps (atom with maps). Those maps have keys {:name val}. If a new map is added, then I create a corresponding atom for this map by parsing its :name key.
"The summary of the question is as follows: one needs to create atoms at will with unknown yet symbols at unknown times. "
This sounds like a solution looking for a problem. I would generally suggest you try another way of achieving whatever the actual functionality is without generating vars at runtime, but if you must, you should use intern and leave out the macro stuff.
You cannot solve this with macros since macros are expanded at compile time, meaning that in
(defn new-atom [a]
(do
(swap! atom-pool conj a)
(populate-atoms)))
populate-atoms is expanded only once; when the (defn new-atom ...) form is compiled, but you're attempting to change its expansion when new-atom is called (which necessarily happens later).
#JoostDiepenmaat is right about why populate-atoms is not behaving as expected. You simply cannot do this using macros, and it is generally best to avoid generating vars at runtime. A better solution would be to define your atom-pool as a map of keywords to atoms:
(def atom-pool
(atom {:a1 (atom #{}) :a2 (atom #{})}))
Then you don't need atom-symbols or populate-atoms because you're not dealing with vars at compile-time, but typical data structures at run-time. Your new-atom function could look like this:
(defn new-atom [kw]
(swap! atom-pool assoc kw (atom #{})))
EDIT: If you don't want your new-atom function to override existing atoms which might contain actual data instead of just #{}, you can check first to see if the atom exists in the atom-pool:
(defn new-atom [kw]
(when-not (kw #atom-pool)
(swap! atom-pool assoc kw (atom #{}))))
I've already submitted one answer to this question, and I think that that answer is better, but here is a radically different approach based on eval:
(def atom-pool (atom ["a1" "a2"]))
(defn new-atom! [name]
(load-string (format "(def %s (atom #{}))" name)))
(defn populate-atoms! []
(doseq [x atom-pool]
(new-atom x)))
format builds up a string where %s is substituted with the name you're passing in. load-string reads the resulting string (def "name" (atom #{})) in as a data structure and evals it (this is equivalent to (eval (read-string "(def ...)
Of course, then we're stuck with the problem of only defining atoms that don't already exist. We could change the our new-atom! function to make it so that we only create an atom if it doesn't already exist:
(defn new-atom! [name]
(when-not (resolve (symbol name))
(load-string (format "(def %s (atom #{}))" name name))))
The Clojure community seems to be against using eval in most cases, as it is usually not needed (macros or functions will do what you want in 99% of cases*), and eval can be potentially unsafe, especially if user input is involved -- see Brian Carper's answer to this question.
*After attempting to solve this particular problem using macros, I came to the conclusion that it either cannot be done without relying on eval, or my macro-writing skills just aren't good enough to get the job done with a macro!
At any rate, I still think my other answer is a better solution here -- generally when you're getting way down into the nuts & bolts of writing macros or using eval, there is probably a simpler approach that doesn't involve metaprogramming.
Given a list of names for variables, I want to set those variables to an expression.
I tried this:
(doall (for [x ["a" "b" "c"]] (def (symbol x) 666)))
...but this yields the error
java.lang.Exception: First argument to def must be a Symbol
Can anyone show me the right way to accomplish this, please?
Clojure's "intern" function is for this purpose:
(doseq [x ["a" "b" "c"]]
(intern *ns* (symbol x) 666))
(doall (for [x ["a" "b" "c"]] (eval `(def ~(symbol x) 666))))
In response to your comment:
There are no macros involved here. eval is a function that takes a list and returns the result of executing that list as code. ` and ~ are shortcuts to create a partially-quoted list.
` means the contents of the following lists shall be quoted unless preceded by a ~
~ the following list is a function call that shall be executed, not quoted.
So ``(def ~(symbol x) 666)is the list containing the symboldef, followed by the result of executingsymbol xfollowed by the number of the beast. I could as well have written(eval (list 'def (symbol x) 666))` to achieve the same effect.
Updated to take Stuart Sierra's comment (mentioning clojure.core/intern) into account.
Using eval here is fine, but it may be interesting to know that it is not necessary, regardless of whether the Vars are known to exist already. In fact, if they are known to exist, then I think the alter-var-root solution below is cleaner; if they might not exist, then I wouldn't insist on my alternative proposition being much cleaner, but it seems to make for the shortest code (if we disregard the overhead of three lines for a function definition), so I'll just post it for your consideration.
If the Var is known to exist:
(alter-var-root (resolve (symbol "foo")) (constantly new-value))
So you could do
(dorun
(map #(-> %1 symbol resolve (alter-var-root %2))
["x" "y" "z"]
[value-for-x value-for-y value-for z]))
(If the same value was to be used for all Vars, you could use (repeat value) for the final argument to map or just put it in the anonymous function.)
If the Vars might need to be created, then you can actually write a function to do this (once again, I wouldn't necessarily claim this to be cleaner than eval, but anyway -- just for the interest of it):
(defn create-var
;; I used clojure.lang.Var/intern in the original answer,
;; but as Stuart Sierra has pointed out in a comment,
;; a Clojure built-in is available to accomplish the same
;; thing
([sym] (intern *ns* sym))
([sym val] (intern *ns* sym val)))
Note that if a Var turns out to have already been interned with the given name in the given namespace, then this changes nothing in the single argument case or just resets the Var to the given new value in the two argument case. With this, you can solve the original problem like so:
(dorun (map #(create-var (symbol %) 666) ["x" "y" "z"]))
Some additional examples:
user> (create-var 'bar (fn [_] :bar))
#'user/bar
user> (bar :foo)
:bar
user> (create-var 'baz)
#'user/baz
user> baz
; Evaluation aborted. ; java.lang.IllegalStateException:
; Var user/baz is unbound.
; It does exist, though!
;; if you really wanted to do things like this, you'd
;; actually use the clojure.contrib.with-ns/with-ns macro
user> (binding [*ns* (the-ns 'quux)]
(create-var 'foobar 5))
#'quux/foobar
user> quux/foobar
5
Evaluation rules for normal function calls are to evaluate all the items of the list, and call the first item in the list as a function with the rest of the items in the list as parameters.
But you can't make any assumptions about the evaluation rules for special forms or macros. A special form or the code produced by a macro call could evaluate all the arguments, or never evaluate them, or evaluate them multiple times, or evaluate some arguments and not others. def is a special form, and it doesn't evaluate its first argument. If it did, it couldn't work. Evaluating the foo in (def foo 123) would result in a "no such var 'foo'" error most of the time (if foo was already defined, you probably wouldn't be defining it yourself).
I'm not sure what you're using this for, but it doesn't seem very idiomatic. Using def anywhere but at the toplevel of your program usually means you're doing something wrong.
(Note: doall + for = doseq.)