4clojure: set-intersection, recursive lambda - clojure

I am attempting to write a recursive lambda function (accepting two arguments) that finds the intersection between two (potentially) unsorted sets. Here is the code, which I believe most will find straight forward:
(fn intersection [a b]
(fn inner [x y out]
(if (empty? x) out
(if (nil? (some ((set (first x)) y )))
(inner (rest x) y out))))
(inner (rest x) y (cons (first x) out))
(inner a b '[])
)
I hope to use this lambda function intersection in place of the underscore _ that follows:
(= (__ #{0 1 2 3} #{2 3 4 5}) #{2 3})
However, this code fails to compile, insisting that Java is Unable to resolve symbol: inner in this context...
Any suggestions?
source: http://www.4clojure.com/problem/81

You could try :
#(set (filter %1 %2))
Since sets are functions (see another useful example there). The syntax with %1 and %2 is the same as writing :
(fn [s1 s2] (set (filter s1 s2)))
Or even more succinctly :
(comp set filter)
Regarding the inner error, you simply misplaced the parens (but I don't really see the logic otherwise) :
(fn intersection [a b]
(fn inner [x y out]
(if (empty? x) out
(if (nil? (some ((set (first x)) y )))
(inner (rest x) y out)))
(inner (rest x) y (cons (first x) out))
(inner a b '[])))
If you insist on building the set manually (which I did not so long ago), you could end up with something like that :
(fn [s1 s2]
(reduce #(if (contains? s2 %2) (conj %1 %2) %1) #{} s1))
But really the first solution is the most elegant.

Related

Writing a lazy-as-possible unfoldr-like function to generate arbitrary factorizations

problem formulation
Informally speaking, I want to write a function which, taking as input a function that generates binary factorizations and an element (usually neutral), creates an arbitrary length factorization generator. To be more specific, let us first define the function nfoldr in Clojure.
(defn nfoldr [f e]
(fn rec [n]
(fn [s]
(if (zero? n)
(if (empty? s) e)
(if (seq s)
(if-some [x ((rec (dec n)) (rest s))]
(f (list (first s) x))))))))
Here nil is used with the meaning "undefined output, input not in function's domain". Additionally, let us view the inverse relation of a function f as a set-valued function defining inv(f)(y) = {x | f(x) = y}.
I want to define a function nunfoldr such that inv(nfoldr(f , e)(n)) = nunfoldr(inv(f) , e)(n) when for every element y inv(f)(y) is finite, for each binary function f, element e and natural number n.
Moreover, I want the factorizations to be generated as lazily as possible, in a 2-dimensional sense of laziness. My goal is that, when getting some part of a factorization for the first time, there does not happen (much) computation needed for next parts or next factorizations. Similarly, when getting one factorization for the first time, there does not happen computation needed for next ones, whereas all the previous ones get in effect fully realized.
In an alternative formulation we can use the following longer version of nfoldr, which is equivalent to the shorter one when e is a neutral element.
(defn nfoldr [f e]
(fn [n]
(fn [s]
(if (zero? n)
(if (empty? s) e)
((fn rec [n]
(fn [s]
(if (= 1 n)
(if (and (seq s) (empty? (rest s))) (first s))
(if (seq s)
(if-some [x ((rec (dec n)) (rest s))]
(f (list (first s) x)))))))
n)))))
a special case
This problem is a generalization of the problem of generating partitions described in that question. Let us see how the old problem can be reduced to the current one. We have for every natural number n:
npt(n) = inv(nconcat(n)) = inv(nfoldr(concat2 , ())(n)) = nunfoldr(inv(concat2) , ())(n) = nunfoldr(pt2 , ())(n)
where:
npt(n) generates n-ary partitions
nconcat(n) computes n-ary concatenation
concat2 computes binary concatenation
pt2 generates binary partitions
So the following definitions give a solution to that problem.
(defn generate [step start]
(fn [x] (take-while some? (iterate step (start x)))))
(defn pt2-step [[x y]]
(if (seq y) (list (concat x (list (first y))) (rest y))))
(def pt2-start (partial list ()))
(def pt2 (generate pt2-step pt2-start))
(def npt (nunfoldr pt2 ()))
I will summarize my story of solving this problem, using the old one to create example runs, and conclude with some observations and proposals for extension.
solution 0
At first, I refined/generalized the approach I took for solving the old problem. Here I write my own versions of concat and map mainly for a better presentation and, in the case of concat, for some added laziness. Of course we can use Clojure's versions or mapcat instead.
(defn fproduct [f]
(fn [s]
(lazy-seq
(if (and (seq f) (seq s))
(cons
((first f) (first s))
((fproduct (rest f)) (rest s)))))))
(defn concat' [s]
(lazy-seq
(if (seq s)
(if-let [x (seq (first s))]
(cons (first x) (concat' (cons (rest x) (rest s))))
(concat' (rest s))))))
(defn map' [f]
(fn rec [s]
(lazy-seq
(if (seq s)
(cons (f (first s)) (rec (rest s)))))))
(defn nunfoldr [f e]
(fn rec [n]
(fn [x]
(if (zero? n)
(if (= e x) (list ()) ())
((comp
concat'
(map' (comp
(partial apply map)
(fproduct (list
(partial partial cons)
(rec (dec n))))))
f)
x)))))
In an attempt to get inner laziness we could replace (partial partial cons) with something like (comp (partial partial concat) list). Although this way we get inner LazySeqs, we do not gain any effective laziness because, before consing, most of the computation required for fully realizing the rest part takes place, something that seems unavoidable within this general approach. Based on the longer version of nfoldr, we can also define the following faster version.
(defn nunfoldr [f e]
(fn [n]
(fn [x]
(if (zero? n)
(if (= e x) (list ()) ())
(((fn rec [n]
(fn [x] (println \< x \>)
(if (= 1 n)
(list (list x))
((comp
concat'
(map' (comp
(partial apply map)
(fproduct (list
(partial partial cons)
(rec (dec n))))))
f)
x))))
n)
x)))))
Here I added a println call inside the main recursive function to get some visualization of eagerness. So let us demonstrate the outer laziness and inner eagerness.
user=> (first ((npt 5) (range 3)))
< (0 1 2) >
< (0 1 2) >
< (0 1 2) >
< (0 1 2) >
< (0 1 2) >
(() () () () (0 1 2))
user=> (ffirst ((npt 5) (range 3)))
< (0 1 2) >
< (0 1 2) >
< (0 1 2) >
< (0 1 2) >
< (0 1 2) >
()
solution 1
Then I thought of a more promising approach, using the function:
(defn transpose [s]
(lazy-seq
(if (every? seq s)
(cons
(map first s)
(transpose (map rest s))))))
To get the new solution we replace the previous argument in the map' call with:
(comp
(partial map (partial apply cons))
transpose
(fproduct (list
repeat
(rec (dec n)))))
Trying to get inner laziness we could replace (partial apply cons) with #(cons (first %) (lazy-seq (second %))) but this is not enough. The problem lies in the (every? seq s) test inside transpose, where checking a lazy sequence of factorizations for emptiness (as a stopping condition) results in realizing it.
solution 2
A first way to tackle the previous problem that came to my mind was to use some additional knowledge about the number of n-ary factorizations of an element. This way we can repeat a certain number of times and use only this sequence for the stopping condition of transpose. So we will replace the test inside transpose with (seq (first s)), add an input count to nunfoldr and replace the argument in the map' call with:
(comp
(partial map #(cons (first %) (lazy-seq (second %))))
transpose
(fproduct (list
(partial apply repeat)
(rec (dec n))))
(fn [[x y]] (list (list ((count (dec n)) y) x) y)))
Let us turn to the problem of partitions and define:
(defn npt-count [n]
(comp
(partial apply *)
#(map % (range 1 n))
(partial comp inc)
(partial partial /)
count))
(def npt (nunfoldr pt2 () npt-count))
Now we can demonstrate outer and inner laziness.
user=> (first ((npt 5) (range 3)))
< (0 1 2) >
(< (0 1 2) >
() < (0 1 2) >
() < (0 1 2) >
() < (0 1 2) >
() (0 1 2))
user=> (ffirst ((npt 5) (range 3)))
< (0 1 2) >
()
However, the dependence on additional knowledge and the extra computational cost make this solution unacceptable.
solution 3
Finally, I thought that in some crucial places I should use a kind of lazy sequences "with a non-lazy end", in order to be able to check for emptiness without realizing. An empty such sequence is just a non-lazy empty list and overall they behave somewhat like the lazy-conss of the early days of Clojure. Using the definitions given below we can reach an acceptable solution, which works under the assumption that always at least one of the concat'ed sequences (when there is one) is non-empty, something that holds in particular when every element has at least one binary factorization and we are using the longer version of nunfoldr.
(def lazy? (partial instance? clojure.lang.IPending))
(defn empty-eager? [x] (and (not (lazy? x)) (empty? x)))
(defn transpose [s]
(lazy-seq
(if-not (some empty-eager? s)
(cons
(map first s)
(transpose (map rest s))))))
(defn concat' [s]
(if-not (empty-eager? s)
(lazy-seq
(if-let [x (seq (first s))]
(cons (first x) (concat' (cons (rest x) (rest s))))
(concat' (rest s))))
()))
(defn map' [f]
(fn rec [s]
(if-not (empty-eager? s)
(lazy-seq (cons (f (first s)) (rec (rest s))))
())))
Note that in this approach the input function f should produce lazy sequences of the new kind and the resulting n-ary factorizer will also produce such sequences. To take care of the new input requirement, for the problem of partitions we define:
(defn pt2 [s]
(lazy-seq
(let [start (list () s)]
(cons
start
((fn rec [[x y]]
(if (seq y)
(lazy-seq
(let [step (list (concat x (list (first y))) (rest y))]
(cons step (rec step))))
()))
start)))))
Once again, let us demonstrate outer and inner laziness.
user=> (first ((npt 5) (range 3)))
< (0 1 2) >
< (0 1 2) >
(< (0 1 2) >
() < (0 1 2) >
() < (0 1 2) >
() () (0 1 2))
user=> (ffirst ((npt 5) (range 3)))
< (0 1 2) >
< (0 1 2) >
()
To make the input and output use standard lazy sequences (sacrificing a bit of laziness), we can add:
(defn lazy-end->eager-end [s]
(if (seq s)
(lazy-seq (cons (first s) (lazy-end->eager-end (rest s))))
()))
(defn eager-end->lazy-end [s]
(lazy-seq
(if-not (empty-eager? s)
(cons (first s) (eager-end->lazy-end (rest s))))))
(def nunfoldr
(comp
(partial comp (partial comp eager-end->lazy-end))
(partial apply nunfoldr)
(fproduct (list
(partial comp lazy-end->eager-end)
identity))
list))
observations and extensions
While creating solution 3, I observed that the old mechanism for lazy sequences in Clojure might not be necessarily inferior to the current one. With the transition, we gained the ability to create lazy sequences without any substantial computation taking place but lost the ability to check for emptiness without doing the computation needed to get one more element. Because both of these abilities can be important in some cases, it would be nice if a new mechanism was introduced, which would combine the advantages of the previous ones. Such a mechanism could use again an outer LazySeq thunk, which when forced would return an empty list or a Cons or another LazySeq or a new LazyCons thunk. This new thunk when forced would return a Cons or perhaps another LazyCons. Now empty? would force only LazySeq thunks while first and rest would also force LazyCons. In this setting map could look like this:
(defn map [f s]
(lazy-seq
(if (empty? s) ()
(lazy-cons
(cons (f (first s)) (map f (rest s)))))))
I have also noticed that the approach taken from solution 1 onwards lends itself to further generalization. If inside the argument in the map' call in the longer nunfoldr we replace cons with concat, transpose with some implementation of Cartesian product and repeat with another recursive call, we can then create versions that "split at different places". For example, using the following as the argument we can define a nunfoldm function that "splits in the middle" and corresponds to an easy-to-imagine nfoldm. Note that all "splitting strategies" are equivalent when f is associative.
(comp
(partial map (partial apply concat))
cproduct
(fproduct (let [n-half (quot n 2)]
(list (rec n-half) (rec (- n n-half))))))
Another natural modification would allow for infinite factorizations. To achieve this, if f generated infinite factorizations, nunfoldr(f , e)(n) should generate the factorizations in an order of type ω, so that each one of them could be produced in finite time.
Other possible extensions include dropping the n parameter, creating relational folds (in correspondence with the relational unfolds we consider here) and generically handling algebraic data structures other than sequences as input/output. This book, which I have just discovered, seems to contain valuable relevant information, given in a categorical/relational language.
Finally, to be able to do this kind of programming more conveniently, we could transfer it into a point-free, algebraic setting. This would require constructing considerable "extra machinery", in fact almost making a new language. This paper demonstrates such a language.

How to iterate through a list and make lists of the elements

I am trying to convert logical functions in clojure. I want the user to be able to type in (convert '(and x y z) to produce (nor (nor x) (nor y) (nor z). So I am creating a list with first element nor, and then trying to make the rest of the elements lists that are created when going through a for loop. However the for loop just combines all the lists, and keeps the nor outside of it. I also want to know how to skip the first element in the list but that's not my priority right now. I'm kinda new to clojure and can't figure out how to just return all of the lists to be put into the bigger list. The not and or function aren't related to the problem.
(defn lookup
"Look up a value, i, in map m and returns the result if it exists.
Otherwise returns i."
[i m]
(get m i i))
(defn makelist
[l]
(for[i[l]] (list 'nor i)))
(defn convert
[l]
(let [p1 (first l)]
(cond
(= p1 'not) (map (fn [i] (lookup i '{not nor})) l)
(= p1 'or) (list 'nor (map(fn [i] (lookup i '{or nor})) l))
(= p1 'and) (list 'nor (makelist l))
:else (print "error"))))
The output I get is (nor ((nor (and x y z)))). The output I want is (nor (nor and) (nor x) (nor y) (nor z). I don't want the (nor and) either but until I can figure out how to skip the first element I just want to be able to separate the lists out.
There are two problems that I can see:
makelist has (for [i [l]] ...) so it only produces a single item where i is bound to the whole of the incoming list l -- what you want here is (for [i l] ...) so that each element of l is processed,
convert's clause for and creates a list with two elements: nor and the result of (makelist l) -- what you want here is (cons 'nor (makelist l)) so that you get a list with nor as the first element and then all of the elements of the result of calling makelist.
I haven't checked the other two parts of convert to see whether you have similar errors, but with the two changes above (convert '(and x y z)) will produce (nor (nor and) (nor x) (nor y) (nor z))
just for fun: i would mentally expand and generalize your task to rewriting data structures according to some rules, so you could declare (possibly recursive) rewrite rules to transform any input to any desired output in general. (and to practice clojure)
let's start with simple conversion function:
(defn convert [rules data]
(if-let [res (some (fn [[condition rewrite]]
(when (condition data) (rewrite data)))
rules)]
res
data))
it finds first rule that suits your input (if any) and applies it's transformation function:
(def my-rules [[sequential? (fn [data] (map #(convert my-rules %) data))]
[number? inc]
[keyword? (comp clojure.string/upper-case name)]])
#'user/my-rules
user> (convert my-rules [:hello :guys "i am" 30 [:congratulate :me]])
;;=> ("HELLO" "GUYS" "i am" 31 ("CONGRATULATE" "ME"))
with this approach, your rules would look something like this:
(def rules
[[(every-pred coll? (comp #{'not} first)) (fn [data] (map (partial convert [[#{'not} (constantly 'nor)]]) data))]
[(every-pred coll? (comp #{'or} first)) (fn [data] (map (partial convert [[#{'or} (constantly 'nor)]]) data))]
[(every-pred coll? (comp #{'and} first)) (fn [[_ & t]] (cons 'nor (map #(list 'nor %) t)))]])
#'user/rules
user> (convert rules '(and x y z))
;;=> (nor (nor x) (nor y) (nor z))
ok it works, but looks rather ugly. Still we can elimnate some repetitions introducing couple of basic functions for checkers and transformers:
(defn first-is
"returns a function checking that the input is collection and it's head equals to value"
[value]
(every-pred coll? (comp #{value} first)))
transforming your rules to:
(def rules
[[(first-is 'not) (fn [data] (map (partial convert [[#{'not} (constantly 'nor)]]) data))]
[(first-is 'or) (fn [data] (map (partial convert [[#{'or} (constantly 'nor)]]) data))]
[(first-is 'and) (fn [[_ & t]] (cons 'nor (map #(list 'nor %) t)))]])
#'user/rules
user> (convert rules '(and x y z))
;;=> (nor (nor x) (nor y) (nor z))
and then introducing replacing rewrite rule:
(defn replacing
([new] [(constantly true) (constantly new)])
([old new] [#{old} (constantly new)]))
leading us to
(def rules
[[(first-is 'not) (fn [data] (map (partial convert [(replacing 'not 'nor)]) data))]
[(first-is 'or) (fn [data] (map (partial convert [(replacing 'or 'nor)]) data))]
[(first-is 'and) (fn [[_ & t]] (cons 'nor (map #(list 'nor %) t)))]])
now we can see that there is a demand on a function, transforming every item in collection. let's introduce it:
(defn convert-each [rules]
(fn [data] (map #(convert rules %) data)))
(def rules
[[(first-is 'not) (convert-each [(replacing 'not 'nor)])]
[(first-is 'or) (convert-each [(replacing 'or 'nor)])]
[(first-is 'and) (fn [[_ & t]] (cons 'nor (map #(list 'nor %) t)))]])
user> (convert rules '(or x y z))
;;=> (nor x y z)
user> (convert rules '(and x y z))
;;=> (nor (nor x) (nor y) (nor z))
now it is much better, but the last clause is still kind of ugly. I can think of introducing the function that transforms head and tail with separate rules and then conses transformed head and tail:
(defn convert-cons [head-rules tail-conversion]
(fn [[h & t]] (cons (convert head-rules h) (tail-conversion t))))
(defn transforming [transformer]
[(constantly true) transformer])
(def rules
[[(first-is 'not) (convert-each [(replacing 'not 'nor)])]
[(first-is 'or) (convert-each [(replacing 'or 'nor)])]
[(first-is 'and) (convert-cons [(replacing 'nor)]
(convert-each [(transforming #(list 'nor %))]))]])
user> (convert rules '(and x y z))
;;=> (nor (nor x) (nor y) (nor z))

Clojure: Implementing the some function

I'm new to clojure and tried to implement the some function (for some specific tests):
(my-some even? [1 2 3 4]) => true
(my-some #{3 4} [1 2 3 4]) => 3
(my-some zero? [1 2 3 4]) => nil
That's what I came up with so far:
(defn my-some [f x]
(loop [[y & t] x]
(if (empty? t) nil
(if (f y)
(f y)
(recur t)))))
I could imagine there are more idiomatic approaches.
Any suggestions?
Firstly, you have a bug: [[y & t] x] destructures x, but the following empty? check on t means you are ignoring the last element in the sequence. You can see this with
(my-some even? [2])
=> nil
You can replace (if (empty? x) nil (else-form)) with when and seq:
(when (seq x) ...)
you can then use first and next to deconstruct the sequence:
(defn my-some [f x]
(when (seq x)
(if (f (first x))
(f (first x))
(recur f (rest x)))))
the call to recur is then back into my-some so you need to pass the predicate f.
you can replace (if x x (else ....)) with (or x (else ...)):
(defn my-some [f x]
(when (seq x)
(or (f (first x)) (recur f (next x)))))
you can compare this with the implementation of some

Clojure: How to count occurrences in a list?

I'm still pretty new to clojure, so I apologize if this a bit trivial. Basically, the issue is in the "then" part of the if statement: (if (symbol? (first slist)).
;counts the number of occurences of
(defn count-occurrences [s slist]
(if (empty? slist)
0
(if (symbol? (first slist))
(if (= (first slist) s)
(+ 1 (count-occurrences s (rest slist)))
(+ 0 (count-occurrences s (rest slist))))
(count-occurrences s (first slist))))) ;Problem on this line
(println (count-occurrences 'x '((f x) y (((x z) x)))))
To count elements in a nested list, you could try this function:
(defn count-occurrences [s slist]
(->> slist
flatten
(filter #{s})
count))
Test:
user> (count-occurrences 'x '((f x) y (((x z) x))))
;; => 3
user> (count-occurrences 'y '((f x) y (((x z) x))))
;; => 1
user> (count-occurrences 'z '((f x) y (((x z) x))))
;; => 1
As Diego Basch commented, the skeleton of your algorithm ought to be
(defn count-occurrences [s slist]
(+ (count-occurrencies s (first slist))
(count-occurrencies s (rest slist))))
... which has one or two little problems:
It never terminates.
It doesn't deal with a symbol.
It doesn't deal with an empty list.
slist might not be a list, and eventually, through first calls,
won't be.
How do we deal with these problems?
First, test whether were dealing with a symbol.
If we aren't, assume it's a list and test whether it's empty.
If not, apply the skeleton recursion.
... giving us something like this:
(defn count-occurrences [s x]
(if (symbol? x)
(if (= x s) 1 0)
(if (empty? x)
0
(+ (count-occurrences s (first x))
(count-occurrences s (rest x))))))
... which works:
(count-occurrences 'x '((f x) y (((x z) x))))
;3
This solution has several problems (which you'll come to appreciate) that make Mark's answer superior in practice. However, if you're trying to get to grips with recursion, this will do nicely.

Defining my own max function with variable arguments

I'm learning Clojure solving the problems listed on 4clojure. One of the exercises is to create your own max function with variable arguments.
I'm trying to solve this easy problem using the REPL and I got to this solution:
(defn my-max
[first & more] (calc-max first more))
(defn calc-max
[m x]
(cond (empty? x) m
(> (first x) m) (calc-max (first x) (rest x))
:else calc-max m (rest x)))
Which works fine but the exercise doesn't allow the use of def and therefore I must crunch both functions into one. When I replace the calc-max reference with its code the result is:
(defn my-max
[first & more]
((fn calc-max
[m x]
(cond (empty? x) m
(> (first x) m) (calc-max (first x) (rest x))
:else calc-max m (rest x)))
first more))
But this code doesn't work and returns the next error:
user=> (my-max 12 3 4 5 612 3)
java.lang.ClassCastException: java.lang.Integer cannot be cast to clojure.lang.IFn (NO_SOURCE_FILE:0)
I guess this error comes from trying to evaluate the result of the calc-max function and I guess it's a syntax error on my part, but I can't figure out how to resolve it.
Here is the function I used to solve it. The point is not to use max at all.
(fn [& args] (reduce (fn [x y] (if (> x y) x y) ) args ) )
Real error is that you called parameter first - it rebinds real first function to number! Just change name to something other, and your variant will work. Although it maybe better explicitly name function, instead of calling anonymous function, for example, you can declare calc-max as local function using letfn, for example. So your my-max will look like:
(defn my-max [ff & more]
(letfn [(calc-max [m x]
(cond (empty? x) m
(> (first x) m) (calc-max (first x)
(rest x))
:else (calc-max m (rest x))))]
(calc-max ff more)))
Although, I think, that you can write simpler code:
(defn my-max [& more] (reduce max more))
Your function doesn't work because first in fn treated as function and not as input value. So when you write
user=> (my-max 12 3 4 5 612 3)
it's talling that can't cast 12 to function. Simply, it can be rewrited as
(defn my-max1 [fst & more]
((fn calc-max [m x]
(cond (empty? x) m
(> (first x) m) (calc-max (first x) (rest x))
:else (calc-max m (rest x))))
fst more))
or even without fn
(defn my-max [x & xs]
(cond (empty? xs) x
(> (first xs) x) (recur (first xs) (rest xs))
:else (recur x (rest xs))))
To elaborate a little more on the exception that you are seeing: whenever Clojure throws something like
java.lang.Integer cannot be cast to clojure.lang.IFn
at you it means that it tried to call a function but the thing it tried to call was not a function but something else. This usually occurs when you have code like this
(smbl 1 2 3)
If smbl refers to a function, clojure will execute it with parameters 1 2 and 3. But if smbl doesn't refer to a function then you will see an error like the one above. This was my pointer in looking through your code and, as 4e6 pointed out, (first x) is the culprit here because you named your function argument first.
Not as good as the reduce but ok ba:
(fn [& args]
(loop [l args, maxno (first args)]
(if (empty? l)
maxno
(if (> maxno (first l) )
(recur (rest l) maxno)
(recur (rest l) (first l))))))
Can use cond I suppose