Conditional composition operator - clojure

I'd like to know if there exists some built-in function composition operator in clojure allowing me to rewrite something like:
(def first-or-identity #(if (sequential? %) (first %) (identity %)))
into a shorter:
(def first-or-identity (if-composition sequential? first identity)
--
The use case would be to be able to write something along those lines:
(def eventbus-pub
(async/pub eventbus (if-composition sequential? first identity)))
Thanx!

You can do this with a function:
(defn if-composition [tester truer falser]
(fn [x]
(if (tester x) (truer x) (falser x))))
For example,
(map
(if-composition even? #(quot % 2) #(inc (* 3 %)))
(range 10))
;(0 4 1 10 2 16 3 22 4 28)
It's worth while making the last argument identity by default:
(defn if-composition
([tester truer] (if-composition tester truer identity))
([tester truer falser]
... ))
For example,
(map (if-composition odd? #(* 2 %)) (range 10))
;(0 2 2 6 4 10 6 14 8 18)
Now we can write your example as
(def first-or-identity (if-composition sequential? first))

Related

How to write a max function in clojure for a '()

I very new to Clojure as of a couple of days ago.
I am trying to create a my-max function which must work as below
(my-max '(8 18 98 55 4 5 6)) => 98
I've looked at other similar questions such as Defining my own max function with variable arguments
I've tried to write functions like the ones in the post, but I don't understand why they don't work when the it's written with the parenthesis, for example
(my-max '(8 18 98 55 4 5 6)) (8 18 98 55 4 5 6)
but if I remove the list and write (my-max 8 18 98 55 4 5 6) => 98, then it works.
I am trying to understand how can I write a max function that works for a () and if it's empty then it should return nil.
The function that I tried to work on
(defn my-max [x & xs]
(cond (empty? xs) x
(> (first xs) x) (recur (first xs) (rest xs))
:else (recur x (rest xs))))
You can apply built-in max or function from akond's answer:
(defn my-max [lst]
(when (seq lst)
(apply max lst)))
(my-max '(8 18 98 55 4 5 6))
=> 98
(my-max '())
=> nil
(require
'[clojure.test :refer [is]])
(letfn [(my-max
([] nil)
([x] x)
([a b] (if (< a b) b a))
([a b & rest] (reduce my-max (conj rest a b))))]
(is (= nil (my-max)))
(is (= 1 (my-max 1)))
(is (= 2 (my-max 1 2)))
(is (= 3 (my-max 1 3 2)))
(is (= 4 (my-max 4 1 3 2))))
You can also use reduce:
(defn my-max [& args]
(reduce #(if (< %1 %2) %2 %1) args))
reduce begins with first argument collected in args and compares it with the next element in args. If the next element - which is inserted as %2 is bigger than the first element %1, then the output of the inner anonymous function is %2 otherwise %1. This output becomes the %1 in the next call of the anonymous function and the next element becomes %2. Thus it is as if the inner function compares always the next element with the recent maximal element and keeps the bigger of both for the next comparison. Finally the last output of the inner anonymous function will be returned.
and one more, just for fun:
you can employ max-key for that:
(def my-max (partial apply max-key #(or % ##-Inf) nil))
user> (my-max [1 2 3])
;;=> 3
user> (my-max [])
;;=> nil
user> (my-max [1])
;;=> 1
user> (my-max [2 1])
;;=> 2

a version of `sequence` that doesn't do chunking

I'd like to have a version of sequence that doesn't do the chunking of 32 elements. Currently, this code will output
(def peek #(doto % (print " ")))
(def pause #(do (Thread/sleep 10)
%))
(take 2 (->> (range 100)
(sequence (comp (map peek)
(map pause)
(map inc)))))
;; prints 0 1 2 3 4 <..etc..> 32
;; => (0, 1)
I'd like a version of it so that it only iterates through the elements that it needs
(take 2 (->> (range 100)
(iter-sequence (comp (map peek)
(map pause)
(map inc)))))
;; prints 0 1
;; => (0, 1)
Is there a way to do this?
I had to change a couple of things to get it working. The first is to cut and paste sequence code and replace clojure.lang.RT/chunkIteratorSeq with an alternative version of clojure.lang.IteratorSeq that has exposed public constructor methods.
The reason being is that the clojure.lang.IteratorSeq/create has a check to iter.next() on L27 which will block if the source is blocking.
(defn seqiter
{:added "1.0"
:static true}
([coll] coll)
([xform coll]
(IteratorSeq.
(TransformerIterator/create xform (clojure.lang.RT/iter coll))))
([xform coll & colls]
(IteratorSeq.
(TransformerIterator/createMulti
xform
(map #(clojure.lang.RT/iter %) (cons coll colls))))))

Clojure: map function with updatable state

What is the best way of implementing map function together with an updatable state between applications of function to each element of sequence? To illustrate the issue let's suppose that we have a following problem:
I have a vector of the numbers. I want a new sequence where each element is multiplied by 2 and then added number of 10's in the sequence up to and including the current element. For example from:
[20 30 40 10 20 10 30]
I want to generate:
[40 60 80 21 41 22 62]
Without adding the count of 10 the solution can be formulated using a high level of abstraction:
(map #(* 2 %) [20 30 40 10 20 10 30])
Having count to update forced me to "go to basic" and the solution I came up with is:
(defn my-update-state [x state]
(if (= x 10) (+ state 1) state)
)
(defn my-combine-with-state [x state]
(+ x state))
(defn map-and-update-state [vec fun state update-state combine-with-state]
(when-not (empty? vec)
(let [[f & other] vec
g (fun f)
new-state (update-state f state)]
(cons (combine-with-state g new-state) (map-and-update-state other fun new-state update-state combine-with-state))
)))
(map-and-update-state [20 30 40 50 10 20 10 30 ] #(* 2 %) 0 my-update-state my-combine-with-state )
My question: is it the appropriate/canonical way to solve the problem or I overlooked some important concepts/functions.
PS:
The original problem is walking AST (abstract syntax tree) and generating new AST together with updating symbol table, so when proposing the solution to the problem above please keep it in mind.
I do not worry about blowing up stack, so replacement with loop+recur is not
my concern here.
Is using global Vars or Refs instead of passing state as an argument a definite no-no?
You can use reduce to accumulate a pair of the number of 10s seen so far and the current vector of results.:
(defn map-update [v]
(letfn [(update [[ntens v] i]
(let [ntens (+ ntens (if (= 10 i) 1 0))]
[ntens (conj v (+ ntens (* 2 i)))]))]
(second (reduce update [0 []] v))))
To count # of 10 you can do
(defn count-10[col]
(reductions + (map #(if (= % 10) 1 0) col)))
Example:
user=> (count-10 [1 2 10 20 30 10 1])
(0 0 1 1 1 2 2)
And then a simple map for the final result
(map + col col (count-10 col)))
Reduce and reductions are good ways to traverse a sequence keeping a state. If you feel your code is not clear you can always use recursion with loop/recur or lazy-seq like this
(defn twice-plus-ntens
([coll] (twice-plus-ntens coll 0))
([coll ntens]
(lazy-seq
(when-let [s (seq coll)]
(let [item (first s)
new-ntens (if (= 10 item) (inc ntens) ntens)]
(cons (+ (* 2 item) new-ntens)
(twice-plus-ntens (rest s) new-ntens)))))))
have a look at map source code evaluating this at your repl
(source map)
I've skipped chunked optimization and multiple collection support.
You can make it a higher-order function this way
(defn map-update
([mf uf coll] (map-update mf uf (uf) coll))
([mf uf val coll]
(lazy-seq
(when-let [s (seq coll)]
(let [item (first s)
new-status (uf item val)]
(cons (mf item new-status)
(map-update mf uf new-status (rest s))))))))
(defn update-f
([] 0)
([item status]
(if (= item 10) (inc status) status)))
(defn map-f [item status]
(+ (* 2 item) status))
(map-update map-f update-f in)
The most appropriate way is to use function with state
(into
[]
(map
(let [mem (atom 0)]
(fn [val]
(when (== val 10) (swap! mem inc))
(+ #mem (* val 2)))))
[20 30 40 10 20 10 30])
also see
memoize
standard function

Clojure vector -> vector function using # and % syntax sugar?

Is it possible to code using #, %1, %2 for the below?
(defn fib-step [[a b]]
[b (+ a b)])
(defn fib-seq []
(map first (iterate fib-step [0 1])))
user> (take 20 (fib-seq))
(0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181)
In short, I'd like to know how to write
vector -> vector function using # and % syntax sugar.
Thanks
You can easily produce a vector using the #() reader form with the -> threading macro. For example, the following two functions are equivalent:
(fn [a b] [b a])
#(-> [%2 %])
However, if you need to do destructuring, as in your case, you're best off just sticking with one of the fn forms with an explicit parameter list. The best you'd get with #() is something like this:
#(-> [(% 1) (+ (% 0) (% 1))])
or
#(-> [(% 1) (apply + %)])
Using the higher-order juxt function is another nice way to create vectors, but unfortunately in this case it doesn't buy you much either:
(def fib-step (juxt second #(apply + %)))
I think out of all the options, using fn is still the best fit because of its easy support for destructuring:
(fn [[a b]] [b (+ a b)])
I would suggest making fib-step take 2 parameters rather than a vector as that would make things more clear that this function need two values whereas a vector as param means it can take any number of values as param (in the form of the vector).
(def fib-step #(-> [%2 (+ %1 %2)]))
(defn fib-seq []
(map first (iterate (partial apply fib-step) [0 1])))
I think using the vector function is clearer than the (-> [...]) "trick":
#(vector (% 1) (apply + %))
Though in this instance, with destructuring, I'd just use a named function or (fn [...] ...) anyway.
Here is the code:
(def step #(-> [(% 1) (+ (% 0) (% 1))]))
(def fib #(map first (iterate step [0 1])))
(println
(take 20 (fib))
)
or
(def step #(-> [(% 1) (+ (% 0) (% 1))]))
(def fib (->> [0 1]
(iterate step)
(map first)))
(println
(->> fib
(take 20))
))

Applying multiple filters to a collection in a thrush in Clojure

The following code
(let [coll [1 2 3 4 5]
filters [#(> % 1) #(< % 5)]]
(->> coll
(filter (first filters))
(filter (second filters))))
Gives me
(2 3 4)
Which is great, but how do I apply all the filters in coll without having to explicitly name them?
There may be totally better ways of doing this, but ideally I'd like to know an expression that can replace (filter (first filters)) (filter (second filters)) above.
Thanks!
Clojure 1.3 has a new every-pred function, which you could use thusly:
(filter (apply every-pred filters) coll)
This should work :-
(let [coll [1 2 3 4 5]
filters [#(> % 1) #(< % 5)]]
(filter (fn [x] (every? #(% x) filters)) coll)
)
I can't say I'm very proud of the following, but at least it works and allows for infinite filters:
(seq
(reduce #(clojure.set/intersection
(set %1)
(set %2)) (map #(filter % coll) filters)))
If you can use sets in place of seqs it would simplify the above code as follows:
(reduce clojure.set/intersection (map #(filter % coll) filters))
(let [coll [1 2 3 4 5]
filters [#(> % 1) #(< % 5)]]
(reduce (fn [c f] (filter f c)) coll filters))