Anything wrong with the code? looks like binding doesn't work with iterate?
(def ^:dynamic *step* 1)
(defn incr [n] (+ n *step*))
(take 3 (binding [*step* 2] (iterate incr 1)))
gives
'(1 2 3)
not
'(1 3 5)
The problem is that iterate returns a lazy sequence. So, the first call to incr function occurs outside of binding scope when you're trying to print the sequence.
Technically, your incr function is not free from side-effects just because it uses ^:dynamic variable.
If you want to use binding with lazy sequences you should force the evaluation of your sequence somewhere inside of a binding scope, e.g.:
(binding [*step* 2]
(doall (take 3 (iterate incr 1))))
; => (1 3 5)
Related
I am a newbie to clojure (and functional programming for that matter) and I was trying to do some basic problems. I was trying to find the nth element in a sequence without recursion.
so something like
(my-nth '(1 2 3 4) 2) => 3
I had a hard time looping through the list and returning when i found the nth element. I tried a bunch of different ways and the code that I ended up with is
(defn sdsu-nth
[input-list n]
(loop [cnt n tmp-list input-list]
(if (zero? cnt)
(first tmp-list)
(recur (dec cnt) (pop tmp-list)))))
This gives me an exception which says "cant pop from empty list"
I dont need code, but if someone could point me in the right direction it would really help!
You are using the function pop, which has different behavior for different data structures.
user> (pop '(0 1 2 3 4))
(1 2 3 4)
user> (pop [0 1 2 3 4])
[0 1 2 3]
user> (pop (map identity '(0 1 2 3 4)))
ClassCastException clojure.lang.LazySeq cannot be cast to clojure.lang.IPersistentStack clojure.lang.RT.pop (RT.java:640)
Furthermore, you are mixing calls to pop with calls to first. If iterating, use peek/pop or first/rest as pairs, mixing the two can lead to unexpected results. first / rest are the lowest common denominator, if you want to generalize over various sequential types, use those, and they will coerce the sequence to work if they can.
user> (first "hello")
\h
user> (first #{0 1 2 3 4})
0
user> (first {:a 0 :b 1 :c 2})
[:c 2]
With your function, replacing pop with rest, we get the expected results:
user> (defn sdsu-nth
[input-list n]
(loop [cnt n tmp-list input-list]
(if (zero? cnt)
(first tmp-list)
(recur (dec cnt) (rest tmp-list)))))
#'user/sdsu-nth
user> (sdsu-nth (map identity '(0 1 2 3 4)) 2)
2
user> (sdsu-nth [0 1 2 3 4] 2)
2
user> (sdsu-nth '(0 1 2 3 4) 2)
2
user> (sdsu-nth "01234" 2)
\2
given a list as list_nums, take up to n + 1 then from that return the last element which is nth.
(fn [list_nums n] (last (take (inc n) list_nums)))
and alternatively:
#(last (take (inc %2) %1))
proof:
(= (#(last (take (inc %2) %1)) '(4 5 6 7) 2) 6) ;; => true
What you would really want to do is use the built-in nth function as it does exactly what you're asking:
http://clojuredocs.org/clojure_core/clojure.core/nth
However, since you're learning this is still a good exercise. Your code actually works for me. Make sure you're giving it a list and not a vector -- pop does something different with vectors (it returns the vector without the last item rather than the first -- see here).
Your code works fine for lists if supplied index is not equal or greater then length of sequence (you've implemented zero indexed nth). You get this error when tmp-list gets empty before your cnt gets to the zero.
It does not work so well with vectors:
user> (sdsu-nth [1 2 3 4] 2)
;; => 1
user> (sdsu-nth [10 2 3 4] 2)
;; => 10
it seems to return 0 element for every supplied index. As noisesmith noticed it happens because pop works differently for vectors because of their internal structure. For vectors pop will remove elements form the end, and then first returns first value of any vector.
How to fix: use rest instead of pop, to remove differences in behavior of your function when applied to lists and vectors.
(fn [xs n]
(if (= n 0)
(first xs)
(recur (rest xs) (dec n))))
One more way that I thought of doing this and making it truly non recursive (ie without for/recur) is
(defn sdsu-nth
[input-list n]
(if (zero? (count input-list))
(throw (Exception. "IndexOutOfBoundsException"))
(if (>= n (count input-list))
(throw (Exception. "IndexOutOfBoundsException"))
(if (neg? n)
(throw (Exception. "IndexOutOfBoundsException"))
(last (take (+ n 1) input-list))))))
I have a function that produces lazy-sequences called a-function.
If I run the code:
(map a-function a-sequence-of-values)
it returns a lazy sequence as expected.
But when I run the code:
(mapcat a-function a-sequence-of-values)
it breaks the lazyness of my function. In fact it turns that code into
(apply concat (map a-function a-sequence-of-values))
So it needs to realize all the values from the map before concatenating those values.
What I need is a function that concatenates the result of a map function on demand without realizing all the map beforehand.
I can hack a function for this:
(defn my-mapcat
[f coll]
(lazy-seq
(if (not-empty coll)
(concat
(f (first coll))
(my-mapcat f (rest coll))))))
But I can't believe that clojure doesn't have something already done. Do you know if clojure has such feature? Only a few people and I have the same problem?
I also found a blog that deals with the same issue: http://clojurian.blogspot.com.br/2012/11/beware-of-mapcat.html
Lazy-sequence production and consumption is different than lazy evaluation.
Clojure functions do strict/eager evaluation of their arguments. Evaluation of an argument that is or that yields a lazy sequence does not force realization of the yielded lazy sequence in and of itself. However, any side effects caused by evaluation of the argument will occur.
The ordinary use case for mapcat is to concatenate sequences yielded without side effects. Therefore, it hardly matters that some of the arguments are eagerly evaluated because no side effects are expected.
Your function my-mapcat imposes additional laziness on the evaluation of its arguments by wrapping them in thunks (other lazy-seqs). This can be useful when significant side effects - IO, significant memory consumption, state updates - are expected. However, the warning bells should probably be going off in your head if your function is doing side effects and producing a sequence to be concatenated that your code probably needs refactoring.
Here is similar from algo.monads
(defn- flatten*
"Like #(apply concat %), but fully lazy: it evaluates each sublist
only when it is needed."
[ss]
(lazy-seq
(when-let [s (seq ss)]
(concat (first s) (flatten* (rest s))))))
Another way to write my-mapcat:
(defn my-mapcat [f coll] (for [x coll, fx (f x)] fx))
Applying a function to a lazy sequence will force realization of a portion of that lazy sequence necessary to satisfy the arguments of the function. If that function itself produces lazy sequences as a result, those are not realized as a matter of course.
Consider this function to count the realized portion of a sequence
(defn count-realized [s]
(loop [s s, n 0]
(if (instance? clojure.lang.IPending s)
(if (and (realized? s) (seq s))
(recur (rest s) (inc n))
n)
(if (seq s)
(recur (rest s) (inc n))
n))))
Now let's see what's being realized
(let [seq-of-seqs (map range (list 1 2 3 4 5 6))
concat-seq (apply concat seq-of-seqs)]
(println "seq-of-seqs: " (count-realized seq-of-seqs))
(println "concat-seq: " (count-realized concat-seq))
(println "seqs-in-seq: " (mapv count-realized seq-of-seqs)))
;=> seq-of-seqs: 4
; concat-seq: 0
; seqs-in-seq: [0 0 0 0 0 0]
So, 4 elements of the seq-of-seqs got realized, but none of its component sequences were realized nor was there any realization in the concatenated sequence.
Why 4? Because the applicable arity overloaded version of concat takes 4 arguments [x y & xs] (count the &).
Compare to
(let [seq-of-seqs (map range (list 1 2 3 4 5 6))
foo-seq (apply (fn foo [& more] more) seq-of-seqs)]
(println "seq-of-seqs: " (count-realized seq-of-seqs))
(println "seqs-in-seq: " (mapv count-realized seq-of-seqs)))
;=> seq-of-seqs: 2
; seqs-in-seq: [0 0 0 0 0 0]
(let [seq-of-seqs (map range (list 1 2 3 4 5 6))
foo-seq (apply (fn foo [a b c & more] more) seq-of-seqs)]
(println "seq-of-seqs: " (count-realized seq-of-seqs))
(println "seqs-in-seq: " (mapv count-realized seq-of-seqs)))
;=> seq-of-seqs: 5
; seqs-in-seq: [0 0 0 0 0 0]
Clojure has two solutions to making the evaluation of arguments lazy.
One is macros. Unlike functions, macros do not evaluate their arguments.
Here's a function with a side effect
(defn f [n] (println "foo!") (repeat n n))
Side effects are produced even though the sequence is not realized
user=> (def x (concat (f 1) (f 2)))
foo!
foo!
#'user/x
user=> (count-realized x)
0
Clojure has a lazy-cat macro to prevent this
user=> (def y (lazy-cat (f 1) (f 2)))
#'user/y
user=> (count-realized y)
0
user=> (dorun y)
foo!
foo!
nil
user=> (count-realized y)
3
user=> y
(1 2 2)
Unfortunately, you cannot apply a macro.
The other solution to delay evaluation is wrap in thunks, which is exactly what you've done.
Your premise is wrong. Concat is lazy, apply is lazy if its first argument is, and mapcat is lazy.
user> (class (mapcat (fn [x y] (println x y) (list x y)) (range) (range)))
0 0
1 1
2 2
3 3
clojure.lang.LazySeq
note that some of the initial values are evaluated (more on this below), but clearly the whole thing is still lazy (or the call would never have returned, (range) returns an endless sequence, and will not return when used eagerly).
The blog you link to is about the danger of recursively using mapcat on a lazy tree, because it is eager on the first few elements (which can add up in a recursive application).
A simple example should demonstrate my problem:
First I define a simple variable:
(def a '(["one" 1] ["two" 2] ["nine" 9]))
;; CASE 1: (This works correctly)
(take-while #(< (second %) 5) a)
Returns: (["one" 1] ["two" 2])
;; CASE 2: (This does not seem to work correctly)
;; The only difference is the '>' instead of '<'
(take-while #(> (second %) 5) a)
Returns: ()
It seems to me that CASE 2 should return (["nine" 9]) ?
Is there a way to debug this to see what I'm missing?
Thanks!
take-while stops after the first failing test. Since the first element fails the test (it isn't greater than five), it never gets to the last one. If you want all elements that pass the test regardless of where they appear in the sequence, use filter instead.
The order of arguments to > is important, try
(take-while #(> 5 (second %)) a)
;=> (["one" 1] ["two" 2])
(drop-while #(> 5 (second %)) a)
;=> (["nine" 9])
Here is the function I'm trying to run...
(defn mongean [cards times]
(let [_cards (transient cards)]
(loop [i 0 c (get cards i) _count (count cards) _current (/ _count 2)]
(assoc! _cards _current c)
(if ((rem i 2) = 0)
(def _newcur (- _current (inc i)))
(def _newcur (+ _current (inc i))))
(if (<= i _count)
(recur (inc i) (get cards i) _count _newcur )))
(persistent! _cards)))
It's resulting in this Exception...
Exception in thread "main" java.lang.ClassCastException: clojure.lang.PersistentHashSet$TransientHashSet cannot be cast to clojure.lang.ITransientAssociative
Being new to clojure, I'd also appreciate any constructive criticism of my approach above. The goal is to take a List, and return a re-ordered list.
I assume that you are trying to implement the Mongean shuffle. Your approach is very imperative and you should try to use a more functional approach.
This would be a possible implementation, were we calculate the final order of the cards (as per Wikipedia formula) and then we use the built-in replace function to do the mapping:
(defn mongean [cards]
(let [num-cards (count cards)
final-order (concat (reverse (range 1 num-cards 2)) (range 0 num-cards 2))]
(replace cards final-order)))
user> (mongean [1 2 3 4 5 6 7 8])
(8 6 4 2 1 3 5 7)
How do you call that function? It looks like you're passing a set, so that its transient version will also be a set and hence can't be used with any of the assoc functions, as they work on associative data structures and vectors:
user=> (assoc #{} :a 1)
ClassCastException clojure.lang.PersistentHashSet cannot be cast to clojure.lang.Associative clojure.lang.RT.assoc (RT.java:691)
user=> (assoc! (transient #{}) :a 1)
ClassCastException clojure.lang.PersistentHashSet$TransientHashSet cannot be cast to clojure.lang.ITransientAssociative clojure.core/assoc! (core.clj:2959)
; the following works as it uses maps and vectors
user=> (assoc {} :a 1)
{:a 1}
user=> (assoc! (transient {}) :a 1)
#<TransientArrayMap clojure.lang.PersistentArrayMap$TransientArrayMap#65cd1dff>
user=> (assoc [] 0 :a)
[:a]
Now, let's try to discuss the code itself. It's a bit hard to follow your code and try to understand what the goal really is without some more hints on what you want to achieve, but as general comments:
you have a times input parameter you don't use at all
you are supposed to use the result of a transient mutation, not assume that the transient will mutate in place
avoid transients if you can, they're only meant as a performance optimization
the binding _current (/ _count 2) is probably not what you want, as (/ 5 2) really returns 5/2 and it seems that you want to use it as a position in the result
constants like _count don't need to be part of the loop binding, you can use the outer let so that you don't have to pass them at each and every iteration
use let instead of def for naming things inside a function
(if ((rem 1 2) = 0)) is definitely not what you want
Now, leaving aside the shuffling algorithm, if you need to rearrange a sequence you might just produce a sequence of new positions, map them with the original cards to produce pairs of [position card] and finally reduce them by placing the card at the new position, using the original sequence as the seed:
(defn generate [coll] ; counts down from (count coll) to 0, change to
; implement your shuffling algorithm
(range (dec (count coll)) -1 -1))
(defn mongean [cards times]
(let [positions (generate cards) ; get the new positions
assemble (fn [dest [pos card]] ; assoc the card at the wanted position
(assoc dest pos card))]
(reduce assemble cards (map vector positions cards))))
If you simply want to shuffle:
(defn mongean [cards times] (shuffle cards))
it seem like clojure's let is sequential and would correspond to a scheme let* .
Does clojure have an unsequential binding mechanism like scheme's let?
I believe binding macro is parallel not sequential.
See: http://clojuredocs.org/clojure_core/clojure.core/binding
letfn is a parallel binding form for functions that exists to allow people to write mutually recursive local functions. It's not quite as general as you seek though it can be used in a pinch.
user> (letfn [(a [] 4)
(b [] c)
(c [] a)]
(a))
4
Binding can be used so long as you are assigning values to things in vars and want dynamic scoping
user> (def ^:dynamic x 4)
#'user/x
user> (defn foo [] x)
#'user/foo
user> (binding [x 8] (+ x (foo)))
16 ; the value of x that gets called by foo is modified by the caller
; yielding 16 instead of 12
user> (binding [x 8 a 7] (+ x (foo)))
; Evaluation aborted.
Unable to resolve var: a in this context
if you try to use parallel bindings the dynamic scoping will give different results than let* would in Scheme
user> (def ^:dynamic a 2)
#'user/a
user> (binding [x 8 a 7] (+ x a))
15
user> (binding [x 8 a (+ x 2)] (+ x a))
14 ; this would be 18 if the binding of x to 8 had been used
; instead the root value of 4 was used.
In general It is most common to bind sequentially or use nested lets if required.
binding doesn't give you the same capability as a parallel let because it depends on the existence of bindings. As mentioned letfn will work as long as you don't mind wrapping your values in functions. Another solution is to write a parallel let using a macro:
(defmacro letp
[bindings & exprs]
(let [bindings (partition 2 bindings)
vars (->> bindings (map first) vec)
values (->> bindings (map second))]
`((fn ~vars ~#exprs)
~#values)))
So the following holds:
(def a 7)
(letp [a 5 b a] b)
;;=> 7