Clojure's eval does not "see" local symbols - clojure

I am experimenting with eval in Clojure:
(let [code_as_data '(if (< sequ) on_true on_false)
sequ [1 3 5]
on_true "sequence is sorted in ascending order"
on_false "sequence is NOT sorted"]
(eval code_as_data))
CompilerException java.lang.RuntimeException: Unable to resolve symbol: sequ in this context, compiling:(/tmp/form-init3253735970468294203.clj:1:25)
How do I define symbols so that they are "seen" by eval?

The simplest way to provide local data to code generated at runtime by eval is to generate a form that takes arguments.
(let [code-as-data '(fn [sequ on-true on-false]
(if (apply < sequ)
on-true
on-false))
f (eval code-as-data)]
(f [1 3 5]
"sequence is sorted in ascending order"
"sequence is NOT sorted"))
Of course, since functions are our standard means of inserting runtime values into known forms, this really doesn't need to use eval at all. The same functionality can be expressed more simply without eval:
(let [f (fn [sequ on-true on-false]
(if (apply < sequ)
on-true
on-false))]
(f [1 3 5]
"sequence is sorted in ascending order"
"sequence is NOT sorted"))
In actual code, the eval version is only needed if the logic needs to be generated at runtime (for example if a user provides a new algorithm). If it is onerous to expect users to write their code as a function, you can do a compromise:
(defn code-with-context
[body sq t else]
(let [f (eval (list 'fn '[sequ on-true on-false] body))]
(f sq t else)))
(code-with-context (read-string "(if (apply < sequ) on-true on-false)")
[1 3 5]
"sequence is sorted in ascending order"
"sequence is NOT sorted")

Eval does not recognize lexical bindings (local ones, like with let), though it recognizes the global/dynamic ones. So one of the solutions is to predefine dynamic vars and eval in dynamic binding context:
user> (def ^:dynamic sequ)
#'user/sequ
user> (def ^:dynamic on_true)
#'user/on_true
user> (def ^:dynamic on_false)
#'user/on_false
user>
(let [code_as_data '(if (apply < sequ) on_true on_false)]
(binding [sequ [1 3 5]
on_true "sequence is sorted in ascending order"
on_false "sequence is NOT sorted"]
(eval code_as_data)))
"sequence is sorted in ascending order"
(notice one little mistake: you use (< sequ) which always returns true, what you need is to (apply < sequ))
as you can see, it is quite ugly, and you don't really want to use it.
One of the possible workarounds is to substitute data into the evaluated code using syntax quoting:
user>
(let [sequ [1 3 5]
on_true "sequence is sorted in ascending order"
on_false "sequence is NOT sorted"
code_as_data `(if (apply < ~sequ) ~on_true ~on_false)]
(eval code_as_data))
"sequence is sorted in ascending order"
another option (that looks more usable to me) is to replace all the symbols you need with their values using walker:
user>
(let [code_as_data '(if (apply < sequ) on_true on_false)
bnd {'sequ [1 3 5]
'on_true "sequence is sorted in ascending order"
'on_false "sequence is NOT sorted"}]
(eval (clojure.walk/postwalk-replace bnd code_as_data)))
"sequence is sorted in ascending order"

Through the unholy magic of macros, you can actually construct a version of eval that mostly does what you want it to.
(defmacro super-unsafe-eval
"Like `eval`, but also exposes lexically-bound variables to eval. This
is almost certainly a bad idea."
[form]
`(eval (list 'let
~(vec (mapcat #(vector `(quote ~%)
`(list 'quote ~%))
(keys &env)))
~form)))
This macro uses the special &env variable to access the local environment. It then constructs a let form which binds all the names that are currently bound in the environment that the macro is expanded in. This makes your code sample work:
(let [code_as_data '(if (< sequ) on_true on_false)
sequ [1 3 5]
on_true "sequence is sorted in ascending order"
on_false "sequence is NOT sorted"]
(super-unsafe-eval code_as_data))
;;=> "sequence is sorted in ascending order"
There's also a slight bug in your program. Calling < with a single argument will always return true. You need to use apply to make it work properly:
(let [code_as_data '(if (apply < sequ) on_true on_false)
on_true "sequence is sorted in ascending order"
on_false "sequence is NOT sorted"]
[(let [sequ [1 3 5]]
(super-unsafe-eval code_as_data))
(let [sequ [1 3 1]]
(super-unsafe-eval code_as_data))])
;;=> ["sequence is sorted in ascending order" "sequence is NOT sorted"]

Related

Calculating image of a Set in Clojure includes nil value?

(defn image-of
"computes the image of the element x under R"
[R x]
(set
(for [r R]
(when (= (first r) x)
(second r)))))
Function idea: Add the second variable in R when it's first is equal to x.
So this function is supposed to compute image of a relation. This is kinda successful. When running a test I get this result:
Input: (image-of #{[1 :a] [2 :b] [1 :c] [3 :a]} 1)
Expected: #{:c :a}
Actual: #{nil :c :a}
So it includes a nil value for some reason. What in the function causes this? I guess I could filter out any nil values but would like to have the solution on a single line.
So the problem was I didn't know exactly how to use when
This solution does it:
(set (for [r R
:when (= (first r) x)]
(second r)))
Let me suggest a different approach.
The natural way to represent a relation in Clojure is as a map from keys to sets (or other collections) of values. A function to convert your collection of pairs to this form is ...
(defn pairs->map [pairs]
(reduce
(fn [acc [key value]]
(assoc acc key (conj (acc key #{}) value)))
{}
pairs))
For example, ...
(pairs->map #{[1 :a] [2 :b] [1 :c] [3 :a]})
=> {2 #{:b}, 1 #{:c :a}, 3 #{:a}}
You can use this map as a function. I you feed it a key, it returns the corresponding value:
({2 #{:b}, 1 #{:c :a}, 3 #{:a}} 1)
=> #{:c :a}
You construct this map once and or all and use it as often as you like. Looking it up as a function is effectively a constant-time operation. But you run through the entire collection of pairs every time you evaluate image-of.

How to filter a sequence and retain evaluated pred values?

This is a scenario I encountered many times, yet didn't find an idiomatic approach for it...
Suppose one would like to use a self-defined self-pred function to filter a seq. This self-pred function returns nil for unwanted elements, and useful information for wanted elements. It is desirable to keep the evaluated self-pred values for these wanted elements.
My general solution is:
;; self-pred is a pred function which returns valuable info
;; in general, they are unique and can be used as key
(let [new-seq (filter self-pred aseq)]
(zipmap (map self-pred new-seq) new-seq))
Basically, it is to call self-pred twice on all wanted elements. I feel it is so ugly...
Wonder if there is any better ways. Much appreciated for any input!
In these scenarios you can use keep, but you have to change your "predicate" function to return the full information you need, or nil, for each item.
For example:
(keep (fn [item]
(when-let [tested (some-test item)]
(assoc item :test-output tested))) aseq)
i use this kind of snippet:
(keep #(some->> % self-pred (vector %)) data)
like this:
user> (keep #(some->> % rseq (vector %)) [[1 2] [] [3 4]])
;;=> ([[1 2] (2 1)] [[3 4] (4 3)])
or if you like more verbose result:
user> (keep #(some->> % rseq (hash-map :data % :result)) [[1 2] [] [3 4]])
;;=> ({:result (2 1), :data [1 2]} {:result (4 3), :data [3 4]})
I wouldn't bother with keep, but would just use plain map & filter like so:
(def data (range 6))
(def my-pred odd?)
(defn zip [& colls] (apply map vector colls)) ; like Python zip
(defn filter-with-pred
[vals pred]
(filter #(first %)
(zip (map pred vals) vals)))
(println (filter-with-pred data my-pred))
with result:
([true 1] [true 3] [true 5])
If self-pred guarantees no duplicate key creation for differing values then I'd reach for reduce (since assoc the same key twice will override the original key value pair):
(reduce #(if-let [k (self-pred %2)]
(assoc %1 k %2)
%1)
{}
aseq)
Else we can use group-by to drive a similar result:
(dissoc (group-by self-pred aseq) nil)
Although not the same since the values will be in vectors: {k1 [v1 ..], k2 [..], ..}. but this guarantees all values are kept.

Return a sequence with the elements not in common to two original sequences by using clojure

I have two sequences, which can be vector or list. Now I want to return a sequence whose elements are not in common to the two sequences.
Here is an example:
(removedupl [1 2 3 4] [2 4 5 6]) = [1 3 5 6]
(removeddpl [] [1 2 3 4]) = [1 2 3 4]
I am pretty puzzled now. This is my code:
(defn remove-dupl [seq1 seq2]
(loop [a seq1 b seq2]
(if (not= (first a) (first b))
(recur a (rest b)))))
But I don't know what to do next.
I encourage you to think about this problem in terms of set operations
(defn extrasection [& ss]
(clojure.set/difference
(apply clojure.set/union ss)
(apply clojure.set/intersection ss)))
Such a formulation assumes that the inputs are sets.
(extrasection #{1 2 3 4} #{2 4 5 6})
=> #{1 6 3 5}
Which is easily achieved by calling the (set ...) function on lists, sequences, or vectors.
Even if you prefer to stick with a sequence oriented solution, keep in mind that searching both sequences is an O(n*n) task if you scan both sequences [unless they are sorted]. Sets can be constructed in one pass, and lookup is very fast. Checking for duplicates is an O(nlogn) task using a set.
I'm still new to Clojure but I think the functional mindset is more into composing functions than actually doing it "by hand", so I propose the following solution:
(defn remove-dupl [seq1 seq2]
(concat
(remove #(some #{%} seq1) seq2)
(remove #(some #{%} seq2) seq1)))
EDIT: I think it is better if we define that remove part as a local function and reuse it:
(defn remove-dupl [seq1 seq2]
(let [removing (fn [x y] (remove #(some #{%} x) y))]
(concat (removing seq1 seq2) (removing seq2 seq1))))
EDIT2: As commented by TimothyPratley
(defn remove-dupl [seq1 seq2]
(let [removing (fn [x y] (remove (set x) y))]
(concat (removing seq1 seq2) (removing seq2 seq1))))
There are several problems with your code.
It doesn't test for the end of either sequence argument.
It steps through b but not a.
It implicitly returns nil when any two sequences have the same
first element.
You want to remove the common elements from the concatenated sequences. You have to work out the common elements first, otherwise you don't know what to remove. So ...
We use
clojure.set/intersection to find the common elements,
concat to stitch the collections together.
remove to remove (1) from (2).
vec to convert to a vector.
Thus
(defn removedupl [coll1 coll2]
(let [common (clojure.set/intersection (set coll1) (set coll2))]
(vec (remove common (concat coll1 coll2)))))
... which gives
(removedupl [1 2 3 4] [2 4 5 6]) ; [1 3 5 6]
(removedupl [] [1 2 3 4]) ; [1 2 3 4]
... as required.

How to transpose a nested vector in clojure

I have the following variable
(def a [[1 2] [3 4] [5 6]])
and want to return
[[1 3 5][2 4 6]]
and if input is
[[1 2] [3 4] [5 6] [7 8 9]] then the required result is
[[1 3 5 7] [2 4 6 8] [9]]
How to do it in clojure?
(persistent!
(reduce
(fn [acc e]
(reduce-kv
(fn [acc2 i2 e2]
(assoc! acc2 i2 ((fnil conj []) (get acc2 i2) e2)))
acc
e))
(transient [])
[[1 2 3] [:a :b] [\a] [111] [200 300 400 500]]))
;;=> [[1 :a \a 111 200] [2 :b 300] [3 400] [500]]
An empty vector can be updated via the update-in fn at the 0th index, a non-empty vector can be, additionally, updated at the index immediately following the last value.
The reduction here is about passing the outer accumulator to the inner reducing function, updating it accordingly, and then returning it back to the outer reducing function, which in turn will pass again to the inner rf for processing the next element.
EDIT: Updated to fastest version.
I like ifett's implementation, though it seems weird to use reduce-kv to build a vector that could be easily build with map/mapv.
So, here is how I would've done it:
(defn transpose [v]
(mapv (fn [ind]
(mapv #(get % ind)
(filter #(contains? % ind) v)))
(->> (map count v)
(apply max)
range)))
(->> (range)
(map (fn [i]
(->> a
(filter #(contains? % i))
(map #(nth % i)))))
(take-while seq))
Notice that this algorithm creates a lazy seq of lazy seqs so you that you will only pay for the transformations you really consume. If you insist on creating vectors instead, wrap the forms in vec at the necessary places - or if you are using Clojurescript or don't mind a Clojure 1.7 alpha use transducers to create vectors eagerly without paying for laziness or immutability:
(into []
(comp
(map (fn [i]
(into [] (comp (filter #(contains? % i))
(map #(nth % i)))
a)))
(take-while seq))
(range))
I find this easy to understand:
(defn nth-column [matrix n]
(for [row matrix] (nth row n)))
(defn transpose [matrix]
(for [column (range (count (first matrix)))]
(nth-column matrix column)))
(transpose a)
=> ((1 3 5) (2 4 6))
nth-column is a list comprehension generating a sequence from the nth element of each sequence (of rows).
Then transpose-matrix is simply iterating over the columns creating a sequence element for each, consisting of (nth-column matrix column) i.e. the sequence of elements for that column.
(map
(partial filter identity) ;;remove nil in each sub-list
(take-while
#(some identity %) ;;stop on all nil sub-list
(for [i (range)]
(map #(get % i) a)))) ;; get returns nil on missing values
Use get to have nil on missing values, iterate (for) on an infinite range, stop on all nil sub-list, remove nil from sub-lists. Add vector constructor before first map and in it's function (first argument) if you really need vectors.
EDIT: please leave a comment if you think this is not useful. We can all learn from mistakes.

Clojure compress vector

I am trying to find a Clojure-idiomatic way to "compress" a vector:
(shift-nils-left [:a :b :c :a nil :d nil])
;=> (true [nil nil :a :b :c :a :d])
(shift-nils-left [nil :a])
;=> (false [nil :a])
(shift-nils-left [:a nil])
;=> (true [nil :a])
(shift-nils-left [:a :b])
;=> (false [:a :b])
In other words, I want to move all of the nil values to the left end of the vector, without changing the length. The boolean indicates whether any shifting occurred. The "outside" structure can be any seq, but the inside result should be a vector.
I suspect that the function will involve filter (on the nil values) and into to add to a vector of nils of the same length as the original, but I'm not sure how to reduce the result back to the original length. I know how to this "long-hand", but I suspect that Clojure will be able to do it in a single line.
I am toying with the idea of writing a Bejeweled player as an exercise to learn Clojure.
Thanks.
I would write it like this:
(ns ...
(:require [clojure.contrib.seq-utils :as seq-utils]))
(defn compress-vec
"Returns a list containing a boolean value indicating whether the
vector was changed, and a vector with all the nils in the given
vector shifted to the beginning."
([v]
(let [shifted (vec (apply concat (seq-utils/separate nil? v)))]
(list (not= v shifted)
shifted))))
Edit: so, the same as what Thomas beat me to posting, but I wouldn't use flatten just in case you end up using some sort of seqable object to represent the jewels.
Maybe this way:
(defn shift-nils-left
"separate nil values"
[s]
(let [s1 (vec (flatten (clojure.contrib.seq/separate nil? s)))]
(list (not (= s s1)) s1)))
A little more low-level approach. It traverses the input seq just once as well as the vector of non-nils once. The two more highlevel approaches traverse the input sequence two times (for nil? and (complenent nil?)). The not= traverses the input a third time in the worst-case of no shift.
(defn compress-vec
[v]
(let [[shift? nils non-nils]
(reduce (fn [[shift? nils non-nils] x]
(if (nil? x)
[(pos? (count non-nils)) (conj nils nil) non-nils]
[shift? nils (conj non-nils x)]))
[false [] []] v)]
[shift? (into nils non-nils)]))
(def v [1 2 nil 4 5 nil 7 8] )
(apply vector (take 8 (concat (filter identity v) (repeat nil))))
This creates a sequence of the non- nil values in the vector using filter and then appends nils to the end of the sequence. This gives the values you want as a sequence and then converts them into a vector. The take 8 ensures that the vector is right size.