I'm trying to create some dynamic code within clojure. In the function below, the idea is that the conditions for the (and) macro will be dynamically generated.
(defn matching-keys [rec match-feed keys]
(> (count (clojure.set/select #(and (for [k keys]
(= (% k) (rec k))))
(set match-feed)))
0))
So if it worked!! then this code would produce an (and) something like this when passed keys of [:tag :attrs]:
(and (= (% :tag) (rec :tag))
(= (% :attrs) (rec :attrs)))
I've been messing around with various `` and~` operators to try to make it work, and am now in a state of confusion. Any guidance is welcome.
Thanks,
Colin
You don't need dynamically generated code for this. Changing the anonymous function to #(every? (fn [k] (= (% k) (rec k))) keys) should do what you want without generating code at runtime.
The ability to use higher-order functions means that you should hardly ever need to dynamically generate code.
You can use eval to evaluate a dynamically built form, e.g.:
(eval '(= 2 3))
Keep in mind that a dynamically evaluated form will have no access to the lexical context. It means that:
(let [a 1 b 2]
(eval '(+ a b)))
will not work.
However, it is still possible to use a dynamic environment:
(def a nil)
(def b nil)
(binding [a 1 b 2]
(eval '(+ a b)))
Related
So I recently learned that I cannot modify parameters in a Clojure function.
I have a big function that takes in a list, then does about 5 different steps to modify it and then returns the output.
But what I'm doing now is
(defn modify [my-list other params]
(if (nil? my-list)
my-list
(let [running my-list]
(def running (filter #(> (count %) 1) my-list))
(def running (adjust-values running))
; a whole bunch of other code with conditions that depend on other parameters and that modify the running list
(if (< (count other) (count my-list))
(def running (something))
(def running (somethingelse)))
(def my-map (convert-list-to-map my-list))
(loop [] .... ) loop through map to do some operation
(def my-list (convert-map-to-list my-map)
running
)))
This doesn't seem correct, but I basically tried writing the code as I'd do in Python cuz I wasn't sure how else to do it. How is it done in Clojure?
Instead of using def inside the modify function, you can have a let with multiple bindings. Actually, def is typically only used at the top-level to define things once and is not meant to be a mechanism to allow for mutability. Here is an example of a let with multiple bindings, which is similar to introducing local variables except that you cannot change them:
(defn modify2 [my-list other params]
(if (nil? my-list)
my-list
(let [a (filter #(> (count %) 1) my-list)
b (adjust-values a)
c (adjust-values1 other b)
d (adjust-values2 params c)]
d)))
Here we introduce new names a, b, c and d for each partial result of the final computation. But it is OK to just have a single binding that gets rebound on each line, that is, you could have a single binding running that gets rebound:
(defn modify2 [my-list other params]
(if (nil? my-list)
my-list
(let [running (filter #(> (count %) 1) my-list)
running (adjust-values running)
running (adjust-values1 other running)
running (adjust-values2 params running)]
running)))
Which one you prefer is a matter of style and taste, there are up and downsides with either approach. The let form to introduce new bindings is a powerful construct, but for this specific example where we have a pipeline of steps, we can use the ->> macro that will generate the code for us. So we would instead write
(defn modify3 [my-list other params]
(if (nil? my-list)
my-list
(->> my-list
(filter #(> (count %) 1))
adjust-values
(adjust-values1 other)
(adjust-values2 params))))
It takes the first macro argument and then passes it in as the last parameter to the function call on the following line. Then the result of that line goes in as a last parameter to the line that follows and so on. If a function call just takes a single argument as is the case for adjust-values in the example above, we don't need to surround it with parentheses. See also the similar -> macro.
To see which code is generated by the ->>, we can use macroexpand:
(macroexpand '(->> my-list
(filter #(> (count %) 1))
adjust-values
(adjust-values1 other)
(adjust-values2 params)))
;; => (adjust-values2 params (adjust-values1 other (adjust-values (filter (fn* [p1__7109#] (> (count p1__7109#) 1)) my-list))))
Added: Summary
If your computation has a pipeline structure, the -> and ->> macros can be used to express that computation concisely. However, if your computation has a general shape where, you will want to use let to associate symbols with results of sub-expressions, so that you can use those symbols in subsequent expressions inside the let form.
Yes, this is the way Clojure was designed: as a functional language with
immutable data (of course with fallbacks to what the host offers if you
want or need it).
So if you want to modify data in consecutive steps, then you can either
chain the calls (looks nicer with the threading macros). E.g.
(->> my-list
(filter #(> (count %) 1))
(adjust-values))
This is the same as:
(adjust-values
(filter #(> (count %) 1)
my-list))
If you prefer to do that in steps (e.g. you want to print intermediate
results or you need them), you can have multiple bindings in the let. E.g.
(let [running my-list
filttered (filter #(> (count %) 1) running)
adjusted (adjust-values filtered)
running ((if (< (count other) (count adjusted)) something somethingelse))
my-map (convert-list-to-map my-list)
transformed-map (loop [] .... )
result (convert-map-to-list transformed-map)]
result)
This returns the adjusted values and holds on to all the things in
between (this does nothing right now with the intermediate results, just an example).
And aside: never ever def inside other forms unless you know what you
are doing; def define top level vars in a namespace - it's not a way
to define mutable variables you can bang on iteratively like you might
be used to from other languages).
I've got a function like this:
(defn magic
[a b c]
(flatten (conj [] a b c)))
So on these inputs I get the following:
(magic 1 2 3) => (1 2 3)
(magic 1 [2 3] 4) => (1 2 3 4)
My question is, is there a better way of doing this?
The problem can be summarised as:
I don't know whether I will get numbers or vectors as input, but I need to return a single flat list
This could be slightly simplified (and generalized) as:
(defn magic [& args]
(flatten (apply list args)))
Or, as pointed out in the comments, it can be simplified even further (since args above is already a seq):
(defn magic [& args]
(flatten args))
Other than that, I don't see much else that can be improved about this. Is there anything in particular that's bothering you about your implementation?
If you can get seqs of seqs then you need to be more careful. And will have to recursively go into the list. There is a clojure native function for this tree-seq see the examples here:
http://clojuredocs.org/clojure_core/clojure.core/tree-seq
You'd want something like this (untested):
(defn nonempty-seq [x]
"returns x as a seq if it's a non-empty seq otherwise nil/false"
(and (coll? x) (seq x)))
(tree-seq nonempty-seq seq expr)
How to make clojure to count '() as nil?
For example:
How to make something like
(if '() :true :false)
;to be
:false
;Or easier
(my-fun/macro/namespace/... (if '() :true :false))
:false
And not just if. In every way.
(= nil '()) or (my-something (= nil '()))
true
And every code to be (= '() nil) save.
(something (+ 1 (if (= nil '()) 1 2)))
2
I was thinking about some kind of regural expression. Which will look on code and replace '() by nil, but there are some things like (rest '(1)) and many others which are '() and I am not sure how to handle it.
I was told that macros allow you to build your own languages. I want to try it by changing clojure. So this is much about "How clojure works and how to change it?" than "I really need it to for my work."
Thank you for help.
'() just isn't the same thing as nil - why would you want it do be?
What you might be looking for though is the seq function, which returns nil if given an empty collection:
(seq [1 2 3])
=> (1 2 3)
(seq [])
=> nil
(seq '())
=> nil
seq is therefore often used to test for "emptiness", with idioms like:
(if (seq coll)
(do-something-with coll)
(get-empty-result))
You say you would like to change Clojure using the macros. Presently, as far as I know, this is not something you could do with the "regular" macro system (terminology fix anyone?). What you would really need (I think) is a reader macro. Things I have seen online (here, for example) seem to say that there exists something like reader macros in Clojure 1.4--but I have no familiarity with this because I really like using clooj as my IDE, and it currently is not using Clojure 1.4. Maybe somebody else has better info on this "extensible reader" magic.
Regardless, I don't really like the idea of changing the language in that way, and I think there is a potentially very good alternative: namely, the Clojure function not-empty.
This function takes any collection and either returns that collection as is, or returns nil if that collection is empty. This means that anywhere you will want () to return nil, you should wrap it not-empty. This answer is very similar to mikera's answer above, except that you don't have to convert your collections to sequences (which can be nice).
Both using seq and not-empty are pretty silly in cases where you have a "hand-written" collection. After all, if you are writing it by hand (or rather, typing it manually), then you are going to know for sure whether or not it is empty. The cases in which this is useful is when you have an expression or a symbol that returns a collection, and you do not know whether the returned collection will be empty or not.
Example:
=> (if-let [c (not-empty (take (rand-int 5) [:a :b :c :d]))]
(println c)
(println "Twas empty"))
;//80% of the time, this will print some non-empty sub-list of [:a :b :c :d]
;//The other 20% of the time, this will return...
Twas empty
=> nil
What about empty? ? It's the most expressive.
(if (empty? '())
:true
:false)
You can override macros and functions. For instance:
(defn classic-lisp [arg]
(if (seq? arg) (seq arg) arg))
(defn = [& args]
(apply clojure.core/= (map classic-lisp args)))
(defmacro when [cond & args]
`(when (classic-lisp ~cond) ~#args))
Unfortunately, you can't override if, as it is a special form and not a macro. You will have to wrap your code with another macro.
Let's make an if* macro to be an if with common-lisp behavior:
(defmacro if* [cond & args]
`(if (classic-lisp ~cond) ~#args)
With this, we can replace all ifs with if*s:
(use 'clojure.walk)
(defn replace-ifs [code]
(postwalk-replace '{if if*} (macroexpand-all code)))
(defmacro clojure-the-old-way [& body]
`(do ~#(map replace-ifs body)))
Now:
=> (clojure-the-old-way (if '() :true :false) )
:false
You should be able to load files and replace ifs in them too:
(defn read-clj-file [filename]
;; loads list of clojure expressions from file *filename*
(read-string (str "(" (slurp filename) ")")))
(defn load-clj-file-the-old-way [filename]
(doseq [line (replace-ifs (read-clj-file filename))] (eval line))
Note that I didn't test the code to load files and it might be incompatible with leiningen or namespaces. I believe it should work with overriden = though.
Why don't when-let and if-let support multiple bindings by default?
So:
(when-let [a ...
b ...]
(+ a b))
...instead of:
(when-let [a ...
(when-let [b ...
(+ a b)))
I am aware that I can write my own macro or use a monad (as described here: http://inclojurewetrust.blogspot.com/2010/12/when-let-maybe.html).
Because (for if-let, at least) it's not obvious what to do with the "else" cases.
At least, motivated by Better way to nest if-let in clojure I started to write a macro that did this. Given
(if-let* [a ...
b ...]
action
other)
it would generate
(if-let [a ...]
(if-let [b ...]
action
?))
and it wasn't clear to me how to continue (there are two places for "else").
You can say that there should be a single alternative for any failure, or none for when-let, but if any of the tests mutate state then things are still going to get messy.
In short, it's a little more complicated than I expected, and so I guess the current approach avoids having to make a call on what the solution should be.
Another way of saying the same thing: you're assuming if-let should nest like let. A better model might be cond, which isn't a "nested if" but more an "alternative if", and so doesn't fit well with scopes... or, yet another way of saying it: if doesn't handle this case any better.
Here is when-let*:
(defmacro when-let*
"Multiple binding version of when-let"
[bindings & body]
(if (seq bindings)
`(when-let [~(first bindings) ~(second bindings)]
(when-let* ~(vec (drop 2 bindings)) ~#body))
`(do ~#body)))
Usage:
user=> (when-let* [a 1 b 2 c 3]
(println "yeah!")
a)
;;=>yeah!
;;=>1
user=> (when-let* [a 1 b nil c 3]
(println "damn! b is nil")
a)
;;=>nil
Here is if-let*:
(defmacro if-let*
"Multiple binding version of if-let"
([bindings then]
`(if-let* ~bindings ~then nil))
([bindings then else]
(if (seq bindings)
`(if-let [~(first bindings) ~(second bindings)]
(if-let* ~(vec (drop 2 bindings)) ~then ~else)
~else)
then)))
Usage:
user=> (if-let* [a 1
b 2
c (+ a b)]
c
:some-val)
;;=> 3
user=> (if-let* [a 1 b "Damn!" c nil]
a
:some-val)
;;=> :some-val
EDIT: It turned out bindings should not be leaked in the else form.
If you use cats, then there is a mlet function that you might find useful :
(use 'cats.builtin)
(require '[cats.core :as m])
(require '[cats.monad.maybe :as maybe])
(m/mlet [x (maybe/just 42)
y nil]
(m/return (+ x y)))
;; => nil
As you can see, the mlet short-circuits when encountering a nil value.
(from section 6.5.1 nil)
Functions with closures seem to break when used with eval.
(eval {:fn (let [x "foo"] (fn [] "x"))})
;=> {:fn #<user$eval14716$fn__14717 user$eval14716$fn__14717#1ddd735>}
(eval {:fn (let [x "foo"] (fn [] x))})
;=> IllegalArgumentException No matching ctor found for class user$eval14740$fn__14741
; clojure.lang.Reflector.invokeConstructor (Reflector.java:166)
I don't really know enough about Clojure (or closure) to know if this is a bug or something which intentionally isn't allowed - can anyone shed some light on this?
Edit: Just to be clear, I'm talking specifically about the way eval handles function objects. AFAIK eval is actually designed to work with java objects, including functions; the example given on the clojure website - (eval (list + 1 2 3)) - passes a function object into eval.
Cloure's eval does not perfectly support function objects. It's not necessarily even closures that cause the problem.
For example, this did not work in Clojure 1.0.0:
(eval {:fn (fn [x] x)})
But this did:
(eval (fn [x] x))
The first example got fixed. The following also works:
(eval (let [x "foo"] (fn [] x)))
But the following still does not work:
(eval {:fn (let [x "foo"] (fn [] x))})
I can't pin it down to a single line in the compiler, but it's something about how literal objects (clojure.lang.Compiler$ObjExpr I think) get handled by eval in different contexts: e.g. at the "top" of an expression versus inside another data structure.
In general, I think, you cannot rely on being able to eval function objects in Clojure, regardless of whether or not they are closures. It happens to work for some simple examples, mostly to simplify the explanation of things like (eval (list + 1 2)). Macros should always return literal source code as data structures, not compiled functions.
Try quoting your argument to eval:
(eval '{:fn (let [x "foo"] (fn [] x))})
;=> {:fn #<user$eval345$fn__346 user$eval345$fn__346#17b6dd83>}
((:fn *1))
;=> "foo"
This is not a bug. The equivalent of (eval (list + 1 2 3)) with a "closure" is (eval (list fn [] "foo")), not (eval (fn [] "foo")).
And (eval (list fn [] "foo")) => Can't take value of a macro: #'clojure.core/fn, again indicating that you're not supposed to do things like that (and there's no need for it anyway).