I can seem to wrap my head around macros in Clojure. I'm probably missing something basic. First, allow me to describe an example of what I want.
(defmacro macrotest [v] `(d ...))
(def a '(b c))
(macroexpand-1 '(macrotest a))
; => (d (b c))
In other words, the var passed to macrotest is resolved, but not evaluated further.
Providing the macro with the value of the var works:
(defmacro macrotest [v] `(d ~v))
(macroexpand-1 '(macrotest (b c)))
; => (d (b c))
But providing the var does not:
(def a '(b c))
(macroexpand-1 '(macrotest a))
; => (d a)
Is it possible to resolve a var in Clojure macro, but not evaluate its value?
EDIT: What I want seems to be possible with eval:
(defmacro macrotest [v] `(d ~(eval v)))
(def a '(b c))
(macroexpand-1 '(macrotest a))
; => (user/d (b c))
Its important to understand that macros evaluate at compile time, not at runtime.
at compile time var a does not yet have a value, so its value is not passed to the macro, only its name. However, when you explicitly pass the "value" - well, then it exists at compile time, and you see that it "works".
Lexical environment
Using eval inside a macro is bad practice. Sure, the following works:
(macroexpand-1 '(macrotest a))
; => (user/d (b c))
... but then, this does not work as expected:
(macroexpand-1 '(let [a "oh no"]
(macrotest a)))
; => (user/d (b c))
Surely you would like the macro to evaluate a as it was defined locally, not using the global variable bound to it, but you cannot because the macro does not evaluate v in the right lexical context. And this is the key to understanding macros: they take code and produce code; any data manipulated by that code is not available to you yet. In other words, the moment at which macros are expanded might be totally unrelated to the time their resulting code is evaluated: anything you evaluate while a macro is being executed is probably evaluated too soon w.r.t. the relevance of your data.
What do you want to do?
There is a form named macrotest which should accepts an argument, v and then perform as-if you had form d applied to it. But:
(macrotest (b c)) should not evaluate (b c), just copy it untouched to produce (d (b c)).
(macrotest a) should evaluate a, which results in a quoted form, and place that form in the resulting code, also returning (d (b c)).
You have a problem here, because the meaning changes radically in one or the other case. Either you evaluate an argument, in which case you must quote (b c) and you write:
(defmacro macrotest [v] `(d ~v))
... which requires that d is ready to handle quoted arguments; or you are okay with the argument being not evaluated.
With the same d as above, you can quote the argument explicitly:
(defmacro macrotest [v] `(d '~v))
However, if d itself is a macro that does not evaluate its argument, you have to avoid the quote in front of ~v.
Related
Is it possible to write a define-values macros in Clojure?
Racket language provides such a thing like define-values form which acts in this way
(define -values '(a b c) (1 2 3))
Where a, b, c are global variables now.
How can I do it in Clojure?
(defmacro defvar [x y]
`(let [a# ~x
b# ~y]
(def b# a#)))
(println (defvar 'a 2))
=> #'user/b__2__auto__
;;;It binds the value to auto generated symbol
define-values doesn't make any sense in Clojure. It makes sense in Racket because values lets one expression evaluate to multiple values. In Clojure, an expression always evaluates to exactly one value: there's no values to extract into definitions.
Of course, you can write a macro def-several-things such that
(def-several-things [x y] [1 2])
expands to
(do (def x 1)
(def y 2))
but this is less readable, not more, so nobody does it.
'() is a syntax sugar for (quote ()). But what does '[] mean? Quote a vector?
For example:
(use '[clojure.test :as t])
(.get '[a b c] 1)
(.containsAll '[a b c] '[b c])
((fnth 5) '[a b c d e])
Precisely. ' is a synonym for quote, so
'[a b c]
is just
(quote [a b c])
quote prevents evaluation of a Clojure code, so quoting the whole vector is essentially the same as quoting every single element of it:
['a 'b 'c]
It allows you to produce a vector of symbols, without explicitly calling symbol function:
[(symbol "a") (symbol "b") (symbol "c")]
My background includes 10 years of common lisp so now I am learning Clojure by writing a symbolic math package with vector (i.e. a, b, c) and Nvector bindings (ab, ac, bc, etc) in namespaces, with the print method defined for these objects.
So when I wrote my deftests in the bottom of the same file as where the binding functions, I had to write (declare a b ab) to avert compiler warnings (which makes perfect sense).
(def G3 (doall (ga-bindall "a b c")))
galg.core=> G3
(+a +b +c +a*b +a*c +b*c +a*b*c +a*b +a*c +b*c +a*b*c)
galg.core=> [a +a -a ab +ab -ab a*b +a*b -a*b abc]
[+a +a -a +a*b +a*b -a*b +a*b +a*b -a*b a*b*c]
(deftest galg-vectors
(declare a b ab) ;<=== required when in same file as definitions
(testing "GALG Vector, Nvector and Sum tests."
(is (= (Vector 'a) a))
(is (= (Vector 'a -1) -a))
(is (= ab (Nvector 'a 'b)))
(is (= (+ 1 a ab) (Sum 1 a ab)))
))
Then when I cleaned up my code by moving the tests to, galg.core-test file as here:
(ns galg.core-test (:use clojure.test galg.core)) ;;<== imports a, b, ab, etc
(deftest galg-vectors
;(declare a b ab) ;<=== must be removed when in separate file
(testing "GALG Vector, Nvector and Sum tests."
(is (= (Vector 'a) a))
(is (= (Vector 'a -1) -a))
(is (= ab (Nvector 'a 'b)))
(is (= (+ 1 a ab) (Sum 1 a ab)))
))
... then, the "already refers to:" compiler error occurs when the (declare a b ab) is present:
CompilerException java.lang.IllegalStateException: a already refers to: #'galg.core/a in namespace: galg.core-test, compiling:(NO_SOURCE_PATH:2:3)
This error seems a bit excessive, since from my thinking, "declare" is really the "promise of a binding" for the compiler, without really defining one.
Any thoughts?
declare is not quite that smart, it doesn't really create the promise that something will be created later, rather it creates it now, and it always creates it in the local namespace, it then leaves it up to you to make sure that it gets a value before it is used, otherwise an exception will be thrown when you try to use the unbound value for something requiring a bound value. def is smart enough to not overwrite a bound value with an unbound one in the case where it was previously defined.
user> (macroexpand-1 '(declare a))
(do (def a))
As you can see, declare declare creates local vars with unbound values it is this local var creation that is triggering the error you see. Because the namespace (`ns) expression already added an entry with that name to your namespace, when your expression:
(declare a b ab)
runs it will expand to:
(do (def a) (def b) (def ab))
which will attempt to create a var in the local namespace named a which triggers the error because that name already refers to another namespace.
If it is done within the same namespace, you can def and declare in any order without error.
user> (def a 0)
#'user/a
user> (declare a)
#'user/a
The problem is that all clojure variables are namespaced. A declare creates the variable in the namespace where it is invoked. Because you have invoked use to refer to the symbols from another namespace, declaring them creates new variables galg.core-test/a, etc., which shadow the ones you were using, galg.core/a etc. The error message is telling you that an unrelated var is shadowing the one previously in scope because of use.
I'm trying to implement this logic in Clojure (just an example):
a = 1 + 5
b = a + 3
c = a + 4
d = c + a
return f(a, b, c, d)
The best code I've managed to write so far looks like:
(let [a (+ 1 5) b (+ a 3) c (+ a 4) d (+ c a)] (f a b c d))
This looks rather cumbersome, mostly because in my real-life case these "add" operations are much more complicated and may take a few lines of code. I would rather prefer to write it like (Lisp style):
(set a (+ 1 5))
(set b (+ a 3))
(set c (+ a 4))
(set d (+ c a))
(f a b c d)
Is it possible in Clojure?
No and that is by intent, as the (set ...) calls you're describing imply the use of mutable state in the way languages like Java and C# do. This is something Clojure actively avoids in order to manage state in a more sane way, something that really becomes important in concurrency. For more information I refer you to the Clojure website.
Furthermore, the let form is not cumbersome, it is a useful scoping tool:
In your example a, b,c and d are all local to let. What this means is that once the instruction pointer steps out of the let, all of those bindings are forgotten.
In contrast, even if your (set...) example were to work, you would have polluted your namespace with all of these ephemeral names.
Actually, you almost found the best solution possible in Clojure:
(let [a (+ 1 5)
b (+ a 3)
c (+ a 4)
d (+ c a)]
(f a b c d))
You can't write Clojure code in imperative style, because it's a functional language. You can't freely use defs either, because all variables in Clojure are immutable. So, ones defined the can't be changed. So, if you want to temporary bind some variables, you should use let.
The set function in Clojure creates a set data type from another collection container as opposed to mutating the values of the variables. However, you could do the following:
(def a (+ 1 5))
(def b (+ a 3))
(def c (+ a 4))
(def d (+ c a))
(f a b c d)
The let statement allows you to do the same thing but not "pollute" your top-level namespace with the a, b , c, and d values. However, if you want to be able to hang on to and reference a, b, c, and d, a def would do the trick.
Clojure is awesome, we all know this, but that's not the point. I'm wondering what the idiomatic way of creating and managing higher-order functions in a Haskell-like way is. In Clojure I can do the following:
(defn sum [a b] (+ a b))
But (sum 1) doesn't return a function: it causes an error. Of course, you can do something like this:
(defn sum
([a] (partial + a))
([a b] (+ a b)))
In this case:
user=> (sum 1)
#<core$partial$fn__3678 clojure.core$partial$fn__3678#1acaf0ed>
user=> ((sum 1) 2)
3
But it doesn't seem like the right way to proceed. Any ideas?
I'm not talking about implementing the sum function, I'm talking at a higher level of abstraction. Are there any idiomatic patterns to follow? Some macro? Is the best way defining a macro or are there alternative solutions?
Someone has already implememented this on the Clojure group. You can specify how many args a function has, and it will curry itself for you until it gets that many.
The reason this doesn't happen by default in Clojure is that we prefer variadic functions to auto-curried functions, I suppose.
I've played a bit with the functions suggested by amalloy. I don't like the explicit specification of the number of argument to curry on. So I've created my custom macro. This is the old way to specific an high order function:
(defn-decorated old-sum
[(curry* 3)]
[a b c]
(+ a b c))
This is my new macro:
(defmacro defn-ho
[fn-name & defn-stuff]
(let [number-of-args (count (first defn-stuff))]
`(defn-decorated ~fn-name [(curry* ~number-of-args)] ~#defn-stuff)))
And this is the new implicit way:
(defn-ho new-sum [a b c] (+ a b c))
As you can see there is no trace of (curry) and other stuff, just define your currified function as before.
Guys, what do you think? Ideas? Suggestions?
Bye!
Alfedo
Edit: I've modified the macro according the amalloy issue about docstring. This is the updated version:
(defmacro defhigh
"Like the original defn-decorated, but the number of argument to curry on
is implicit."
[fn-name & defn-stuff]
(let [[fst snd] (take 2 defn-stuff)
num-of-args (if (string? fst) (count snd) (count fst))]
`(defn-decorated ~fn-name [(curry* ~num-of-args)] ~#defn-stuff)))
I don't like the if statement inside the second binding. Any ideas about making it more succint?
This will allow you to do what you want:
(defn curry
([f len] (curry f len []))
([f len applied]
(fn [& more]
(let [args (concat applied (if (= 0 (count more)) [nil] more))]
(if (< (count args) len)
(curry f len args)
(apply f args))))))
Here's how to use it:
(def add (curry + 2)) ; read: curry plus to 2 positions
((add 10) 1) ; => 11
The conditional with the [nil] is meant to ensure that every application ensures some forward progress to the curried state. There's a long explanation behind it but I have found it useful. If you don't like this bit, you could set args as:
[args (concat applied more)]
Unlike JavaScript we have no way of knowing the arity of the passed function and so you must specify the length you expect. This makes a lot of sense in Clojure[Script] where a function may have multiple arities.