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)))
Related
I was writing an answer for this challenge, when I needed to give a recursive function an optional parameter. I ended up with something kind of equivalent to:
(defn func [a & [b?]]
(if b?
b?
(recur a a)))
My intent was for b? to act as an optional parameter. If it wasn't supplied, it would be defaulted to nil via destructuring.
Instead of running though, it gave me an error:
(func 1)
UnsupportedOperationException nth not supported on this type: Long clojure.lang.RT.nthFrom (RT.java:947)
After some debugging, I realized that for some reason the rest parameter wasn't a list as I'd expect, but just the passed number! The error was coming about because it tried to destructure the number.
I can fix it by getting rid of the wrapper list in the parameter list:
(defn func [a & b]
...
But this just looks wrong. I know the rest parameter should be a list, but b is actually just a number. If I use "unoptimized" recursion, it works as I'd expect:
(defn func2 [a & [b?]]
(if b?
b?
(func2 a a)))
(func2 1)
=> 1
Can anyone explain what's going on here?
This appears to be a known difference
; Note that recur can be surprising when using variadic functions.
(defn foo [& args]
(let [[x & more] args]
(prn x)
(if more (recur more) nil)))
(defn bar [& args]
(let [[x & more] args]
(prn x)
(if more (bar more) nil)))
; The key thing to note here is that foo and bar are identical, except
; that foo uses recur and bar uses "normal" recursion. And yet...
user=> (foo :a :b :c)
:a
:b
:c
nil
user=> (bar :a :b :c)
:a
(:b :c)
nil
; The difference arises because recur does not gather variadic/rest args
; into a seq.
It's the last comment that describes the difference.
In the same way you can convert
(if (something)
something
fallback)
into the shorter version :
(or something fallback)
I was wondering if there is a composition function/elegant builtin for threading a value into the validation of a predicate like :
(when (pred x)
x)
Into something like
(thread-pred pred x)
I could easily build some function or macro to do it, but I'd rather not go NIH here.
It took me way longer than I care to admit - but here you go:
Beware this might explode.
(defmacro -pred->
[pred body]
`(when (~pred ~body) ~body))
(macroexpand-1 '(-pred-> odd? 3))
=> (clojure.core/when (odd? 3) 3)
(-pred-> odd? 3)
=> 3
(-pred-> odd? 2)
=> nil
EDIT: as the comments correctly pointed out it would be wiser to let-bind the body to an autogensym like so:
(defmacro -pred->
[pred body]
`(let [b# ~body]
(when (~pred b#) b#)))
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
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#)
In Scheme I can do something like this:
(define (adder)
(define (one) 1)
(define (two) 2)
(+ (one) (two)))
Calling adder results in 3 while calling one will yield an error since one is only visible within the scope of adder.
In Clojure if I do something similar
(defn adder []
(defn one [] 1)
(defn two [] 2)
(+ (one) (two)))
one and two will pollute my namespace since defn uses def internally which creates bindings in the current namespace.
Is there a function/macro which creates named functions in local scope?
The reason for my question is that I got used to the way Scheme works. Naming my local functions that way often makes my code more readable.
Try letfn:
Takes a vector of function specs and a body, and generates a set of
bindings of functions to their names. All of the names are available
in all of the definitions of the functions, as well as the body.
(defn adder []
(letfn [(one [] 1)
(two [] 2)]
(+ (one) (two))))
Additionally to Alex's excellent answer, any fn can be named.
(defn adder []
(let [one (fn [] 1)
two (fn [] (+ (one) (one)))]
(+ (one) (two))))
This is useful if you already have a let block.
If an fn refers to itself, it needs a name of its own
(defn silly []
(let [constant 5
thing (fn thong
([a] (+ a constant))
([] (inc (thong constant))))]
(* (thing) (thing))))
The name the fn is bound to need not be the same as the name it knows itself by.
If you want a function that is visible to the current namespace but not visible by other namespaces - you can use defn-
defn-
macro
Usage: (defn- name & decls)
same as defn, yielding non-public def
from http://clojuredocs.org/clojure_core/clojure.core/defn-
user=> (ns test)
nil
test=> (defn- foo [] "World!")
#'test/foo
test=> (defn bar [] (str "Hello " (foo)))
#'test/bar
test=> (foo)
"World!"
test=> (bar)
"Hello World!"
test=> (ns playground)
nil
playground=> (test/bar)
"Hello World!"
;; Error will be thrown
;; var: #'test/foo is not public
playground=> (test/foo)