Why does this function not work as expected? - clojure

Why does this function not work as expected?
(defn my-juxt
[& fns]
(if (= 1 (count fns))
(fn [& a] (list (apply (first fns) a)))
(fn [& a]
(cons (apply (first fns) a) ((my-juxt (rest fns)) a)))))
Note: This works -
(defn new-juxt
[& fns]
(fn [& a]
(map #(apply % a) fns)))

The problem is in how varargs are used. my-juxt has params [& fns] while it's given [fns] in the last string. The same is with the function it returns as a result: it expects [& a] while provided [a].
The code below will work (please note two extra apply's there)
(defn my-juxt
[& fns]
(if (= 1 (count fns))
(fn [& a] (list (apply (first fns) a)))
(fn [& a]
(cons (apply (first fns) a)
(apply (apply my-juxt (rest fns)) a)))))

Related

Nesting macros in Clojure

Consider this pseudo code:
(defrc name
"string"
[a :A]
[:div a])
Where defrc would be a macro, that would expand to the following
(let [a (rum/react (atom :A))]
(rum/defc name < rum/reactive []
[:div a]))
Where rum/defc is itself a macro. I came up with the code below:
(defmacro defrc
[name subj bindings & body]
(let [map-bindings# (apply array-map bindings)
keys# (keys map-bindings#)
vals# (vals map-bindings#)
atomised-vals# (atom-map vals#)]
`(let ~(vec (interleave keys# (map (fn [v] (list 'rum/react v)) (vals atomised-vals#))))
(rum/defc ~name < rum/reactive [] ~#body))))
Which almost works:
(macroexpand-all '(defrc aname
#_=> "string"
#_=> [a :A]
#_=> [:div a]))
(let* [a (rum/react #object[clojure.lang.Atom 0x727ed2e6 {:status :ready, :val nil}])] (rum/defc aname clojure.core/< rum/reactive [] [:div a]))
However when used it results in a syntax error:
ERROR: Syntax error at (clojure.core/< rum.core/reactive [] [:div a])
Is this because the inner macro is not being expanded?
Turns out the macro was working correctly but the problem occurred because < was inside the syntax quote it got expanded to clojure.core/<, and Rum simply looks for a quoted <, relevant snippet from Rum's source:
...(cond
(and (empty? res) (symbol? x))
(recur {:name x} next nil)
(fn-body? xs) (assoc res :bodies (list xs))
(every? fn-body? xs) (assoc res :bodies xs)
(string? x) (recur (assoc res :doc x) next nil)
(= '< x) (recur res next :mixins)
(= mode :mixins)
(recur (update-in res [:mixins] (fnil conj []) x) next :mixins)
:else
(throw (IllegalArgumentException. (str "Syntax error at " xs))))...

Clojure take-while and n more items

What's the idiomatic way in Clojure to implement take-while-and-n-more below:
=> (take-while-and-n-more #(<= % 3) 1 (range 10))
(0 1 2 3 4)
My try is:
(defn take-while-and-n-more [pred n coll]
(let
[take-while-result (take-while pred coll)
n0 (count take-while-result)]
(concat
take-while-result
(into [] (take n (drop n0 coll))))))
I would use split-with, which is equivalent of getting results of both take-while and drop-while for the same parameters:
(defn take-while-and-n-more [pred n coll]
(let [[head tail] (split-with pred coll)]
(concat head (take n tail))))
Yet another way:
(defn take-while-and-n-more [pred n coll]
(let [[a b] (split-with pred coll)]
(concat a (take n b))))
The following code is a modified version of Clojures take-while. Where Clojures take-while returns nil as a default case (when the predicate does not match), this one invokes take to take the the additional items after the predicate fails.
Note that unlike versions using split-with, this version traverses the sequence only once.
(defn take-while-and-n-more
[pred n coll]
(lazy-seq
(when-let [s (seq coll)]
(if (pred (first s))
(cons (first s) (take-while-and-n-more pred n (rest s)))
(take n s)))))

idiomatic way to only update the first elem matching a pred in a coll

I have a seq, (def coll '([:a 20] [:b 30] [:c 50] [:d 90]))
I want to iterate through the seq, and modify only the first element that matches a predicate.
The predicate (def pred (fn [[a b]] (> b 30)))
(f pred (fn [[a b]] [a (+ b 2)]) coll) => ([:a 20] [:b 30] [:c 52] [:d 90])
f is the fn I want, which takes a pred, and a fn to apply to the first elem which matches the pred. All the rest of the elems are not modified and returned in the seq.
What is the idiomatic way to do the above?
One possible way is to split the collection with split-with, apply the function f to the first element of the second collection returned by split-with, and concat the elements together again.
(defn apply-to-first [pred f coll]
(let [[h t] (split-with (complement pred) coll)]
(concat h (list (f (first t))) (rest t))))
Note that the pred function in your example should probably look like this:
(def pred #(> (second %) 30))
As with most problems, there is a number of ways to solve it. This is but one of them.
If you're running Clojure 1.5, give this a try:
(reduce
(fn [acc [a b]]
(if (pred b)
(reduced (concat (:res acc) [[a (+ b 2)]] (rest (:coll acc))))
(assoc acc
:res (conj (:res acc) [a b])
:coll (rest (:coll acc)))))
{:coll coll :res []}
coll)
;; ([:a 20] [:b 30] [:c 52] [:d 90])
The key in this algorithm is the use of the reduced (note the 'd') function - it essentially tells reduce to halt the iteration and return the result. From its doc string:
-------------------------
clojure.core/reduced
([x])
Wraps x in a way such that a reduce will terminate with the value x
The code is a bit terse, but it should give you the basic idea.
Hope this helps.
This function is not hard to write recursively "from scratch". Not only is this a good learning exercise, it also produces the best solution: it is as lazy as possible, and does the absolute minimum amount of computation. So far, only one answer to this question is lazy, and that one calls pred twice on all the items before the update occurs: once in the take-while, and once in the drop-while, parts of split-with.
(defn update-first [pred f coll]
(lazy-seq
(when-let [coll (seq coll)]
(if (pred (first coll))
(cons (f (first coll))
(rest coll))
(cons (first coll)
(update-first pred f (rest coll)))))))
To keep it straightforward: find first element, find its index and use assoc to "update" the element at index:
(let [e (first (filter pred coll))
ind (.indexOf coll e)]
(assoc (vec coll) ind ((fn [[a b]] [a (+ b 2)]) e) ))
Dominic's note about pred applies:
(def pred #(> (second %) 30))

Clojure local-variables

I want to create a function (thunk) that will return successive elements in a list. What is the best way to do this? I wrote this code based on an apparently flawed understanding of how local variables in clojure work:
(defn reader-for [commands]
(with-local-vars
[stream commands]
(fn []
(let
[r (var-get stream)]
(if (empty? r)
nil
(let
[cur (first r)
_ (var-set stream (rest r))]
cur))))))
In this code I get:
#<CompilerException java.lang.IllegalStateException: Var null/null is unbound. (Chapel.clj:1)>
which seems to suggest that with-local-vars is dynamically scoped. Is that true? Is there any lexically scoped alternative? Thanks for any help.
If you require mutable state, use one of the clojure reference types:
user=> (defn reader-for [coll]
(let [a (atom coll)]
(fn []
(let [x (first #a)]
(swap! a next)
x))))
#'user/reader-for
user=> (def f (reader-for [1 2 3]))
#'user/f
user=> (f)
1
user=> (f)
2
user=> (f)
3
user=> (f)
nil
Also, let is for lexical scoping, binding is for dynamic scoping.
Edit: the thread-safe version as pointed out by Alan.
(defn reader-for [coll]
(let [r (ref coll)]
#(dosync
(let [x (first #r)]
(alter r next)
x))))
And just for fun, a thread-safe version with atoms (don't do this):
(defn reader-for [coll]
(let [a (atom coll)]
(fn []
(let [ret (atom nil)]
(swap! a (fn [[x & xs]]
(compare-and-set! ret nil x)
xs))
#ret))))

Does 'concat' break the laziness of 'line-seq'?

The following code appears to force line-seq to read 4 lines from file. Is this some kind of buffering mechanism? Do I need to use lazy-cat here? If so, how can I apply a macro to a sequence as if it were variadic arguments?
(defn char-seq [rdr]
(let [coll (line-seq rdr)]
(apply concat (map (fn [x] (println \,) x) coll))))
(def tmp (char-seq (clojure.contrib.io/reader file)))
;,
;,
;,
;,
#'user/tmp
Part of what you're seeing is due to apply, since it will need to realize as many args as needed by the function definition. E.g.:
user=> (defn foo [& args] nil)
#'user/foo
user=> (def bar (apply foo (iterate #(let [i (inc %)] (println i) i) 0)))
1
#'user/bar
user=> (defn foo [x & args] nil)
#'user/foo
user=> (def bar (apply foo (iterate #(let [i (inc %)] (println i) i) 0)))
1
2
#'user/bar
user=> (defn foo [x y & args] nil)
#'user/foo
user=> (def bar (apply foo (iterate #(let [i (inc %)] (println i) i) 0)))
1
2
3
#'user/bar