I was trying to implement xor macro and came up with a problem.
I couldn't use private function in a macro.
Here is the example:
private function
(defn :^private xor-result
[x y]
(if (and x y)
false
(or x y)))
macro
(defmacro xor
([] true)
([x] x)
([x & next]
`(let [first# ~x
second# ~(first next)]
(if (= (count '~next) 1)
(xor-result first# second#)
(xor (xor-result first# second#) ~#(rest next))))))
Here is the Error:
CompilerException java.lang.IllegalStateException: var: #'kezban.core/xor-result is not public
Problem solves when I remove ^:private flag.
Question is: What is the reason of this behaviour?
UPDATE: I can use private function with the following approach.
private function
(defn ^:private xor-result
[x y]
(if (and x y)
false
(or x y)))
new macro
(defmacro xor
([] true)
([x] x)
([x & next]
(let [first x
second `(first '(~#next))
result (xor-result (eval first) (eval second))]
`(if (= (count '~next) 1)
~result
(xor ~result ~#(rest next))))))
If you have a macro in ns1:
(ns ns1)
(defn- my-fun [x] (first x))
(defmacro my-macro [x] (my-fun ~x))
And use it in another namespace:
(ns ns2
(:require [ns1 :refer [my-macro]]))
(my-macro [1 2])
The compiler will call the macro during compilation phase and it will generate code in ns2 namespace and will become:
(ns ns2
(:require [ns1 :refer [my-macro]]))
(ns1/my-fun [1 2])
and this code will be eventually compiled to byte code.
As you can see the compiler will see usage of a ns1's private function in ns2 namespace and will complain about it.
To debug your macros you can use macroexpand to see the result of applying your macro.
You also need to remember that your macros work on your program data: datastructures representing your code (symbols, lists, vectors etc.). For example in your second version of the macro it works symbols as they are, not runtime values bound to them:
(macroexpand '(xor true false))
;; => (if (clojure.core/= (clojure.core/count (quote (false))) 1) true (boot.user/xor true))
(macroexpand '(xor (zero? 1) (zero? 0)))
;; => (if (clojure.core/= (clojure.core/count (quote ((zero? 0)))) 1) false (boot.user/xor false))
As you can see your xor-result function won't be called with the actual runtime values but rather with the data representing your code. xor-result is called in your macro directly during compile time. In the first version of your macro it is used inside of the code generated by the macro and is not called during compilation.
There's a hack you can use if you really do want to access private vars from within a public macro that will be used by other namespaces.
When you resolve the value of a var by referring to it in your code, Clojure checks whether the var is public or private and the compiler will complain if you attempt to access a private var. However you can refer explicitly to the var itself (rather than its value) using the #' syntax, and Clojure will allow this kind of reference even to a private var. You should use a fully-qualified name (use the full namespace name) so that you don't require any particular namespace alias to exist.
So, assuming that the function xor-result lives in a namespace called mynamespace.core, you would invoke the function like:
(#'mynamespace.core/xor-result first# second#)
Related
I am a beginner with Clojure and I received this error while trying to write code in Clojure:
; Syntax error compiling at (src/com/playground/core.clj:17:1).
; Unable to resolve symbol: Example in this context
Here is my code
(ns com.playground.core
(:gen-class))
;; This program displays Hello World
(defn Example []
;; The below code declares a integer variable
(def x 1)
;; The below code declares a float variable
(def y 1.25)
;; The below code declares a string variable
(def str1 "Hello")
(println x)
(println y)
(println str1))
(Example)
I pulled this directly from tutorialspoint and tried to find other people who had the same error but could not find anybody else.
I guess you didn't evaluate that function. Open REPL for this project, evaluate definition for Example and then evaluate (Example).
As you can already see in comments, this code is very bad and you shouldn't learn from that tutorial. But from a beginner point of view, it may be helpful to see what exactly is wrong:
naming conventions: names of functions should be dash-separated-lowercase-words, so no Example, but example.
already mentioned def inside defn. Def creates a global variable, don't use it inside any other definitions. If you need to create some variables inside function, use let.
integer variable and float variable. Clojure uses long and double and created variables will have exactly these types- you can check it yourself with function type.
repeated println (it'll work, but you can also use clojure.string/join with vector and only one println to get the same result)
Improved code:
(defn example []
(let [x 1
y 1.25
str1 "Hello"]
(println (clojure.string/join
"\n"
[x (type x) y (type y) str1]))))
(example)
=>
1
class java.lang.Long
1.25
class java.lang.Double
Hello
You can't declare a definition inside a function.
You need to declare these symbols (variable in other langs) outside. Something like that.
(ns com.play
ground.core
(:gen-class))
(def x 1)
(def y 1.25)
(def str1 "Hello")
(defn Example []
(println x)
(println y)
(println str1))
(Example)
So, when you do it, you're declaring x y and str1 as global and it's not a good practice.
To keep the context of these symbols only inside the function, you need to use the let approach.
(ns com.playground.core
(:gen-class))
(defn Example []
(let [x 1
y 1.25
str1 "Hello"]
(println x)
(println y)
(println str1)))
(Example)
An extra tip is to avoid using camel-case as a way of declaration naming.
Consider to use kebab-case :)
(ns com.playground.core
(:gen-class))
(defn example-function []
(let [x 1
y 1.25
str1 "Hello"]
(println x)
(println y)
(println str1)))
(example-function)
I have a small function used for debugging:
(set! *warn-on-reflection* true)
(defn debug [x] (doto x (->> println :>)))
When I call my function in a loop, I get the following reflection warning:
(loop [i 5] (when (pos? i) (recur (debug (dec i)))))
form-init14269737395101875093.clj:1 recur arg for primitive local: i is not matching primitive, had: Object, needed: long
Auto-boxing loop arg: i
I want to solve the reflection warning. How can I make my function "inherit" the type information from the parameter without explicitly specifying it or replacing it with a macro?
Here is a way that works:
(loop [i (Integer. 5)]
(when (pos? i)
(recur (debug (dec i)))))
with a warning-free result:
lein test tst.demo.core
4
3
2
1
0
It looks like using just plain 5 causes the compiler to use a primitive, which can't be type hinted. Explicitly creating an Integer object sidesteps the problem. I also tried (int 5) which didn't work.
Is there a reason you want to turn on reflection warnings? I normally never use them, especially for debugging.
Update
Note that if you wrap the code in a function like so:
(defn stuff
[arg]
(loop [i arg]
(when (pos? i)
(recur (debug (dec i))))))
there is no problem calling (stuff 5) since function args must always be passed as objects (via autoboxing if necessary).
the problem is that the return type of debug can't be deduced.
this is usually solved with type hints
in your case the following should do the trick:
(defn debug ^long [x] (doto x (->> println :>)))
user> (loop [i 5] (when (pos? i) (recur (debug (dec i)))))
4
3
2
1
0
nil
If, for whatever the reason, you do not want to use a macro, you may want to have a look at definline which seems to preserve type information:
(definline debug2 [x] (doto x (->> println :>)))
The call below, for instance, does not result in a reflection warning:
(.add (debug2 (ArrayList.)) 5)
My initial thought would have been to use a Java class with overloaded methods to achieve something along these lines, of which one method would take a generic argument T and return a T. In addition to this generic method, you would have had to overload that method for the few primitive types because generics only work with boxed values AFAIK. You could then reuse the class below for your debugging purposes:
import clojure.lang.IFn;
public class PassThrough {
private IFn _fn;
public PassThrough(IFn fn) {
_fn = fn;
}
public <T> T invoke(T x) {
_fn.invoke(x);
return x;
}
public long invoke(long x) {
_fn.invoke(x);
return x;
}
public double invoke(double x) {
_fn.invoke(x);
return x;
}
}
This will not work for reference types, though, because of type erasure. So if I would do something like this, I would still get a warning:
(defn debug [x] (doto x (->> println :>)))
(def pt-debug (PassThrough. debug))
(.add (.invoke ^PassThrough pt-debug (ArrayList.)) 9) ;; <-- Reflection warning here when calling .add
I define a macro to bind a symbol derived from a string to the string like this:
lein repl
... Clojure 1.8.0 ...
user=> (defmacro foo [s] `(def ~(symbol s) ~s))
#'user/foo
It works as expected when invoked at top level:
user=> (foo "asdf")
#'user/asdf
user=> asdf
"asdf"
But when I try to map a function that invokes the macro over a sequence, the macro binds the function parameter symbol rather than the one I want:
user=> (map (fn [x] (foo x)) ["qwer"])
(#'user/x)
user=> x
"qwer"
user=> qwer
CompilerException ... Unable to resolve symbol: qwer ...
The following alternative binds the temporary symbol created by Clojure:
user=> (map #(foo %) ["qwer"])
(#'user/p1__1253#)
It also doesn't work when wrapped in doall as suggested by some of the existing answers I researched on StackOverflow.
How can I define a symbol-binding macro that I can map (in a function or otherwise) over a collection of strings?
map is a function and foo is a macro. Since macro expansion happens at compile time and functions are executed at run time, defining a symbol-binding macro that you can map (and thus expand at run time) is impossible.
What you can do is something like this:
(defn foo2 [s]
`(def ~(symbol s) ~s))
(defmacro foos [ss]
`(do ~#(map foo2 ss)))
(foos ["asdf" "qwer"])
asdf ;; => "asdf"
qwer ;; => "qwer"
Now it's the other way around: the macro is expanded using the functions map and foo.
Here is a way of doing it. The solution first shows how the macro foo works, then uses an intermediate solution with a function map-foo-fn and then eval.
The final solution uses a second macro map-foo-mcr. This seems to be needed since (def ...) is a special form. This is similar (but not identical) to the problem of "turtles all the way down" where using a macro in one place requires all callers to also be macros, not functions.
(ns clj.core
(:require
[tupelo.core :as t] ))
(t/refer-tupelo)
(defmacro foo
[arg]
`(def ~(symbol arg) ~arg))
(foo "aa")
(spyx aa)
(defn map-foo-fn
[coll]
(cons 'do
(forv [elem coll]
(list 'foo elem))))
(newline)
(prn (map-foo-fn ["bb"] ))
(eval (map-foo-fn ["bb"] ))
(spyx bb)
(defmacro map-foo-mcr
[coll]
`(do
~#(forv [elem coll]
(list 'foo elem))))
(newline)
(println (macroexpand-1 '(map-foo-mcr ["cc" "dd"] )))
(map-foo-mcr ["cc" "dd"] )
(spyx cc)
(spyx dd)
Results:
aa => "aa"
(do (foo "bb"))
bb => "bb"
(do (foo cc) (foo dd))
cc => "cc"
dd => "dd"
Remember that, while macros can do one thing that functions can't (avoid arg evaluation), macros cannot do other things that functions can. In particular, macros can't be passed to map et al where higher-order-function argument is required.
For more details see http://www.braveclojure.com/writing-macros and search for "Macros All the Way Down"
Note that project.clj needs
:dependencies [
[tupelo "0.9.13"]
for spyx to work
If I write a macro that uses the symb# shortcut to create a gensym which is then bound as a global variable, the exact same symbol gets generated over and over. However, it functions correctly if I call gensym manually. Very simple examples:
(defmacro indirection
[name & body]
`(do (def name# ~#body)
(defn ~name [] name#)))
(indirection foo 3)
(foo) ; ⇒ 3
(indirection goo 5)
(goo) ; ⇒ 5
(foo) ; ⇒ 5
The problem is apparent if you use macroexpand:
(macroexpand '(indirection foo 3))
(do (def name__2863__auto__ 3) (clojure.core/defn foo [] name__2863__auto__))
(macroexpand '(indirection foo 3))
(do (def name__2863__auto__ 3) (clojure.core/defn foo [] name__2863__auto__))
This problem goes away if I call gensym the long way:
(defmacro redirection
[name & body]
(let [rename (gensym)]
`(do (def ~rename ~#body)
(defn ~name [] ~rename))))
(redirection koo 3)
(koo) ; ⇒ 3
(redirection moo 5)
(moo) ; ⇒ 5
(koo) ; ⇒ 3
So, why the difference? What am I missing?
Syntax quoting with ` is actually a reader macro; the form that follows it is transformed by the reader (which translates text to Clojure forms) prior to evaluation. This means that any symbol ending in # within the syntax-quoting is translated to an autogenerated symbol only once, when the text is first read; that autogenerated symbol is then inserted directly into the macro definition, and appears verbatim in the macroexpanion every time that macro is invoked. This can be illustrated easily at the REPL:
user=> `(foo bar#)
(user/foo bar__2288__auto__)
user=> `(foo bar#)
(user/foo bar__2291__auto__)
The typical use case for auto-gen'ed symbols with # is to define local variables inside a quoted let or fn form. There, it does not matter that the same symbol is re-used for multiple macro invocations; it only needs to be unique within each invocation. For instance:
(defmacro indirection
[name body]
`(let [name# ~body]
(defn ~name [] name#)))
Say I want to make a Clojure macro that does the following:
If x is a list calling the function "bar"
return :foobar
else
return x as a string
However, bar is not defined; rather, it is only used internally in the macro, like so:
(foo (bar))
:foobar
(foo 1)
"1"
One could do something like this:
(defmacro foo [x]
(if (and (coll? x) (= (first x) 'bar))
:foobar
(str x)))
This works great for the (bar) case, as well as for literals. However, symbols do not work as intended, giving the symbol name instead of its associated value:
user=> (def y 2)
#'user/y
user=> (foo y)
"y"
One could call the eval function on x before passing it to str, but this causes problem when using the function in let:
user=> (let [a 3 b (foo a)] b)
java.lang.UnsupportedOperationException: Can't eval locals (NO_SOURCE_FILE:89)
Presumably, the problem has to do with symbol resolution, so maybe we try to work something out with syntax-quote:
(defmacro foo [x]
`(if (and (coll? '~x) (= (first '~x) '~'bar))
:foobar
(str ~x)))
Now, the problem is with (foo (bar)), as this expands the else clause to (clojure.core/str (bar)), which throws an exception, as bar is not defined. I then tried doing some shenanigans with eval:
(defmacro foo [x]
`(if (and (coll? '~x) (= (first '~x) '~'bar))
:foobar
(eval '(str ~x))))
But this doesn't work with let bindings again:
user=> (let [a 1 b (foo a)] b)
java.lang.Exception: Unable to resolve symbol: a in this context (NO_SOURCE_FILE:153)
So I'm really at a loss here. It seems as though fixing one problem breaks another. Is there a better, simpler way of making this macro such that it works in the following cases:
In let bindings
With (bar)
With symbols
P.S. If anybody is curious as to why I want to do this, I'm working on a DSL for Yahoo's YQL service and I want to be able to do things like (select (table :t) ...), but I need to be able to pass in symbols, as well as literals.
I believe this should work.
(defmacro foo [x]
(if (and (coll? x) (= (first x) 'bar))
:foobar
`(str ~x)))