#(delay (delay 1)) ; equals to unrealized delay object, containing 1.
Is there an easy (without a head-first macross which tests each block with realized?) way to deref all inner delays recursively?
Arthur's code certainly works for the example you've posted, but here is an example of how you could handle mixed sequences:
(defn deref-delays [x]
(cond
(sequential? x) (map deref-delays x)
(= clojure.lang.Delay (class x)) (recur #x)
:else x))
(deref-delays [1 2 (delay 3) (delay [4 (delay (delay 5)) 6]) 7])
;(1 2 3 (4 5 6) 7)
I'm assuming that if there where many nested delays, you want a function to retrieve the value from the inner most delay?
(defn recursive-deref [delays]
(if (= clojure.lang.Delay (type delays))
(recur #delays)
delays))
#'user/recursive-deref
user> (recursive-deref delays)
1
You can use clojure.walk to do this and preserve structure.
(defn deref-walk [x]
(clojure.walk/prewalk
(fn [e]
(if (delay? e)
(deref-walk (deref e))
e))
x))
Then
(deref-walk (delay {:a 1 :b (delay [1 2 (delay 3) (delay {:c 4})])}))
Results in
{:a 1 :b [1 2 3 {:c 4}]}
Related
I need to quote without namespace and combine it with unquoting. Something like:
'[a b ~c]
Unfortunately, unquoting works only with syntactic quoting:
`[a b ~c]
But then it expands to
[user/a user/b 7]
I would like to expand without namespaces.
What was suggested on clojurians slack channel is as follows:
Use a combination of "quote unquote" for symbols to get rid of namespaces:
`[~'a ~'b ~c]
and this works perfectly.
As a reference, I have been working on a similar capability that doesn't require defensive treatment like ~'a for each symbol you wish to remain unchanged. It isn't published yet, but here is the technique:
;-----------------------------------------------------------------------------
(defn unquote-form?
[arg]
(and (list? arg)
(= (quote unquote) (first arg))))
(defn unquote-splicing-form?
[arg]
(and (list? arg)
(= (quote unquote-splicing) (first arg))))
(defn quote-template-impl
[form]
(walk/prewalk
(fn [item]
(cond
(unquote-form? item) (eval (xsecond item))
(sequential? item) (let [unquoted-vec (apply glue
(forv [it item]
(if (unquote-splicing-form? it)
(eval (xsecond it))
[it])))
final-result (if (list? item)
(t/->list unquoted-vec)
unquoted-vec)]
final-result)
:else item))
form))
(defmacro quote-template
[form]
(quote-template-impl form))
and unit tests to show it in action:
;-----------------------------------------------------------------------------
(def vec234 [2 3 4])
(dotest
(is (td/unquote-form? (quote (unquote (+ 2 3)))))
(is (td/unquote-splicing-form? (quote (unquote-splicing (+ 2 3)))))
(is= (td/quote-template {:a 1 :b (unquote (+ 2 3))})
{:a 1, :b 5})
(is= (td/quote-template {:a 1 :b (unquote (vec (range 3)))})
{:a 1, :b [0 1 2]})
(is= (td/quote-template {:a 1 :b (unquote vec234)})
{:a 1, :b [2 3 4]})
(let [result (td/quote-template (list 1 2 (unquote (inc 2)) 4 5))]
(is (list? result))
(is= result (quote (1 2 3 4 5))))
(is= (td/quote-template [1 (unquote-splicing vec234) 5]) ; unqualified name OK here
[1 2 3 4 5])
(is= (td/quote-template [1 (unquote-splicing (t/thru 2 4)) 5])
[1 2 3 4 5])
(is= (td/quote-template [1 (unquote (t/thru 2 4)) 5])
[1 [2 3 4] 5])
)
So, instead of Clojure's syntax-quote (i.e. backquote), you can use quote-template. Then, use either unquote or unquote-splicing to insert values into the quoted template without having the namespace prepended to other symbols.
I know it is probably not the answer you are looking for by why not use code to construct that thing you want? Why force it to be all done in one expression? You could for example use
(conj '[a b] c)
I am trying to get into Lisps and FP by trying out the 99 problems.
Here is the problem statement (Problem 15)
Replicate the elements of a list a given number of times.
I have come up with the following code which simply returns an empty list []
I am unable to figure out why my code doesn't work and would really appreciate some help.
(defn replicateList "Replicates each element of the list n times" [l n]
(loop [initList l returnList []]
(if (empty? initList)
returnList
(let [[head & rest] initList]
(loop [x 0]
(when (< x n)
(conj returnList head)
(recur (inc x))))
(recur rest returnList)))))
(defn -main
"Main" []
(test/is (=
(replicateList [1 2] 2)
[1 1 2 2])
"Failed basic test")
)
copying my comment to answer:
this line: (conj returnList head) doesn't modify returnlist, rather it just drops the result in your case. You should restructure your program to pass the accumulated list further to the next iteration. But there are better ways to do this in clojure. Like (defn replicate-list [data times] (apply concat (repeat times data)))
If you still need the loop/recur version for educational reasons, i would go with this:
(defn replicate-list [data times]
(loop [[h & t :as input] data times times result []]
(if-not (pos? times)
result
(if (empty? input)
(recur data (dec times) result)
(recur t times (conj result h))))))
user> (replicate-list [1 2 3] 3)
;;=> [1 2 3 1 2 3 1 2 3]
user> (replicate-list [ ] 2)
;;=> []
user> (replicate-list [1 2 3] -1)
;;=> []
update
based on the clarified question, the simplest way to do this is
(defn replicate-list [data times]
(mapcat (partial repeat times) data))
user> (replicate-list [1 2 3] 3)
;;=> (1 1 1 2 2 2 3 3 3)
and the loop/recur variant:
(defn replicate-list [data times]
(loop [[h & t :as data] data n 0 res []]
(cond (empty? data) res
(>= n times) (recur t 0 res)
:else (recur data (inc n) (conj res h)))))
user> (replicate-list [1 2 3] 3)
;;=> [1 1 1 2 2 2 3 3 3]
user> (replicate-list [1 2 3] 0)
;;=> []
user> (replicate-list [] 10)
;;=> []
Here is a version based on the original post, with minimal modifications:
;; Based on the original version posted
(defn replicateList "Replicates each element of the list n times" [l n]
(loop [initList l returnList []]
(if (empty? initList)
returnList
(let [[head & rest] initList]
(recur
rest
(loop [inner-returnList returnList
x 0]
(if (< x n)
(recur (conj inner-returnList head) (inc x))
inner-returnList)))))))
Please keep in mind that Clojure is mainly a functional language, meaning that most functions produce their results as a new return value instead of updating in place. So, as pointed out in the comment, the line (conj returnList head) will not have an effect, because it's return value is ignored.
The above version works, but does not really take advantage of Clojure's sequence processing facilities. So here are two other suggestions for solving your problem:
;; Using lazy seqs and reduce
(defn replicateList2 [l n]
(reduce into [] (map #(take n (repeat %)) l)))
;; Yet another way using transducers
(defn replicateList3 [l n]
(transduce
(comp (map #(take n (repeat %)))
cat
)
conj
[]
l))
One thing is not clear about your question though: From your implementation, it looks like you want to create a new list where each element is repeated n times, e.g.
playground.replicate> (replicateList [1 2 3] 4)
[1 1 1 1 2 2 2 2 3 3 3 3]
But if you would instead like this result
playground.replicate> (replicateList [1 2 3] 4)
[1 2 3 1 2 3 1 2 3 1 2 3]
the answer to your question will be different.
If you want to learn idiomatic Clojure you should try to find a solution without such low level facilities as loop. Rather try to combine higher level functions like take, repeat, repeatedly. If you're feeling adventurous you might throw in laziness as well. Clojure's sequences are lazy, that is they get evaluated only when needed.
One example I came up with would be
(defn repeat-list-items [l n]
(lazy-seq
(when-let [s (seq l)]
(concat (repeat n (first l))
(repeat-list-items (next l) n)))))
Please also note the common naming with kebab-case
This seems to do what you want pretty well and works for an unlimited input (see the call (range) below), too:
experi.core> (def l [:a :b :c])
#'experi.core/
experi.core> (repeat-list-items l 2)
(:a :a :b :b :c :c)
experi.core> (repeat-list-items l 0)
()
experi.core> (repeat-list-items l 1)
(:a :b :c)
experi.core> (take 10 (drop 10000 (repeat-list-items (range) 4)))
(2500 2500 2500 2500 2501 2501 2501 2501 2502 2502)
I am trying to write a function which, given a collection and a sequence of replacements, replaces any lists in the collection with the next replacement in the order they appear.
For example:
(substitute '(+ 1 (* 2 3) 4 (* 5 6) [:a :b]) => (+ 1 :a 4 :b)
(substitute '[1 (2 3 4) (5 6 7)] [:x :y :z]) => [1 :x :y]
(substitute '[(1 2 3) (4 5 6) (7 8 9)] [:x :y]) => [:x :y (7 8 9)]
Currently I have this:
(defn substitute
[form syms]
(if (seq form)
(lazy-seq
(if (and (not-empty syms) (list? (first form)))
(cons
(first syms)
(substitute (rest form) (rest syms)))
(cons
(first form)
(substitute (rest form) syms))))))
However I have two problems. First, I want the output to be the same type as form. I tried doing (into (empty form) (substitute form syms)) but this causes the output to be reversed when form is a list. Second, I am struggling to find a way to make this work on maps (I want to check for a list in both the key and value of each entry).
Any tips or pointers would be much appreciated. Thanks.
Here's an approach using clojure.walk/prewalk to traverse the form in order (pre-order) and using an atom to track what syms remain for substitution:
(defn substitute [form syms]
(let [syms' (atom syms)
depth (atom 0)]
(walk/prewalk
(fn [v]
(cond
(= 1 (swap! depth inc)) v ;; don't examine the input form itself
(list? v) (if-let [sym (first #syms')]
(do (swap! syms' rest)
sym)
v)
:else v))
form)))
The depth atom is to ensure we don't act on the first value which will be form itself, and if it were a list we wouldn't want to substitute the whole thing. At first I just checked (not= form v) but thought that could backfire if your form contains nested forms identical/equal to the outer form. I suspect there's a better way to accomplish this!
prewalk (and postwalk) also relieve you of having to worry about the type of collection you're walking i.e. lists will come out in the correct order.
(substitute '(+ 1 (* 2 3) 4 (* 5 6)) [:a :b])
=> (+ 1 :a 4 :b)
(substitute '[1 (2 3 4) (5 6 7)] [:x :y :z])
=> [1 :x :y]
(substitute '[(1 2 3) (4 5 6) (7 8 9)] [:x :y])
=> [:x :y (7 8 9)]
Using prewalk also allows this to work on maps w/o additional effort:
(substitute {:foo '(1 2 3) '(4 5 6) "hey"} [:a :b])
=> {:foo :a, :b "hey"}
You can also use prewalk-demo to illustrate how the form is traversed:
(walk/prewalk-demo {:foo '(1 2 3) '(4 5 6) "hey"})
Walked: {:foo (1 2 3), (4 5 6) "hey"}
Walked: [:foo (1 2 3)]
Walked: :foo
Walked: (1 2 3)
Walked: 1
Walked: 2
Walked: 3
Walked: [(4 5 6) "hey"]
Walked: (4 5 6)
Walked: 4
Walked: 5
Walked: 6
Walked: "hey"
Thanks to everyone who replied. I think I may have cracked it now.
(defn map-to-vec
[map]
(reduce-kv (fn [vec k v] (into vec [k v])) [] map))
(defn substitute-seq
[form syms]
(if (seq form)
(lazy-seq
(if (and (not-empty syms) (list? (first form)))
(cons
(first syms)
(substitute-seq (rest form) (rest syms)))
(cons
(first form)
(substitute-seq (rest form) syms))))))
(defn substitute
[form syms]
(cond
(list? form) (apply list (sub-syms-seq form syms))
(map? form)
(reduce
(fn [m [k v]] (conj m [k v]))
(empty form)
(partition 2 (sub-syms-seq (map-to-vec form) syms)))
(coll? form) (into (empty form) (sub-syms-seq form syms))))
I wrote a function map-to-vec which converts a map into a vector, such that {:a 1 :b 2 :c 3} becomes [:a 1 :b 2 :c 3] and added a helper function which ensures that the type of the output is the same as the input and, in the case of the input being a map, performs the main function (now called substitute-seq) on the map-to-veced map and then converts it back into a map again.
I'm sure there's still a better and more efficient way to do this but I suppose this works.
I'm trying to come up with some way for the values in a clojure hashmap to refer to each other. Conceptually, something like this:
(def m {:a 1 :b 5 :c (+ (:a m) (:b m))} ;Implies (= (:c m) 6)
This doesn't work, of course since I'm circularly referencing m. I can do something like
(def m {:a 1 :b 5 :c (fn [a b] (+ a b))})
((:c m) (:a m) (:b m)) ;=> 6
but that doesn't really gain anything because I still have to know which a and b to put into the function. Another attempt:
(def m {:a 1 :b 5 :c (fn [m] (+ (:a m) (:b m)))})
((:c m) m) ;=> 6
It's a bit better since I've now internalized the function to a map though not specifically this map. I might try to fix that with something like this
(defn new-get [k m]
(let [v-or-fn (get m k)]
(if (fn? v-or-fn) (v-or-fn m) v-or-fn)))
(def m {:a 1 :b 5 :c (fn [m] (+ (:a m) (:b m)))})
(new-get :a m) ;=> 1
(new-get :b m) ;=> 5
(new-get :c m) ;=> 6
I think this is about the best I can do. Am I missing something more clever?
Couldn't help myself from writing a macro:
(defmacro defmap [name m]
(let [mm (into [] (map (fn [[k v]] `[~k (fn [~name] ~v)]) m))]
`(def ~name
(loop [result# {} mp# (seq ~mm)]
(if (seq mp#)
(let [[k# v#] (first mp#)]
(recur (assoc result# k# (v# result#)) (rest mp#)))
result#)))))
(defmap m [[:a 1]
[:b 5]
[:c (+ (:a m) (:b m))]])
;; m is {:a 1 :b 5 :c 6}
As I've already said in comment above you can use let form:
(def m
(let [a 1 b 5]
{:a a :b b :c (+ a b)}))
This should be fine if you're using values that known only inside m definition. Otherwise you would better to use function parameters as #Michiel shown.
P.S. by the way you're free to use everything inside def you're usually use in clojure. Moreover, sometimes you're free to use let in sugared form inside some other forms (although this let uses different mechanisms than usual let form):
(for [x (...) xs]
:let [y (+ x 1)]
; ...
Since c is a derived value, so a function, of a and b you're probably better of by defining a function that produces this map:
(defn my-map-fn [a b]
{:a a :b b :c (+ a b)})
(def my-map (my-map-fn 1 2))
(:c my-map) ;;=> 3
Here is my take on it:
(defmacro let-map [& bindings]
(let [symbol-keys (->> bindings (partition 2) (map first))]
`(let [~#bindings]
(into {} ~(mapv (fn [k] [(keyword k) k]) symbol-keys)))))
;; if you view it as similar to let, when it's more complicated:
(let-map
a 1
b 5
c (+ a b)) ; => {:a 1, :b 5, :c 6}
;; if you see it as an augmented hash-map, when it's simple enough:
(let-map a 1, b 5, c (+ a b)) ; => {:a 1, :b 5, :c 6}
What I want to do is like following.
(def mystream (stream (range 100)))
(take 3 mystream)
;=> (0 1 2)
(take 3 mystream)
;=> (3 4 5)
(first (drop 1 mystream))
;=> 7
The stream function make sequence side-effectfull like io stream.
I think this is almost impossible.
Here is my attempt.
(defprotocol Stream (first! [this]))
(defn stream [lst]
(let [alst (atom lst)]
(reify Stream
(first! [this]
(let [[fs] #alst]
(swap! alst rest)
fs)))))
(let [mystream (stream (iterate inc 1))]
(map #(if (string? %) (first! mystream) %)
[:a "e" "b" :c "i" :f]))
;=> (:a 1 2 :c 3 :f)
Unfotunately this approach need to implement all function I will use.
Judging by your followup comment to Maurits, you don't need mutation, but rather simply need to emit a new sequence with the elements in the right place.
For example:
(defn replace-when [pred coll replacements]
(lazy-seq
(when (seq coll)
(if (seq replacements)
(if (pred (first coll))
(cons (first replacements)
(replace-when pred (rest coll) (rest replacements)))
(cons (first coll)
(replace-when pred (rest coll) replacements)))
coll))))
user=> (def seq1 [:a :b :c])
#'user/seq1
user=> (def seq2 [:x "i" "u" :y :z "e"])
#'user/seq2
user=> (replace-when string? seq2 seq1)
(:x :a :b :y :z :c)
This won't work with the standard take and drop, but you could quite easily write your own to work on a mutable atom, e.g. you could do something like this:
(def mystream (atom (range 100)))
(defn my-take [n stream]
(let [data #stream
result (take n data)]
(reset! stream (drop n data))
result))
(my-take 3 mystream)
=> (0 1 2)
(my-take 3 mystream)
=> (3 4 5)