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

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

Related

How can I later get access to something created in a let

For example
(def inc-map (let [inum (atom 0)]
{:countup (fn[](swap! inum inc))
:get (fn[](#inum))}))
((inc-map :countup )) ;increase inside value
; ⇒ 1
((inc-map :get)) ;get current value
; ⇒ 1
Can I get access inum when I want to add more functions later?
E.g. I want to do this:
(def inc-map
(assoc inc-map :countdown (fn[] ???)))
How can I access inum at ????
it could be possible, if you expose one more function, say :update, enclosing the inum value.
(def inc-map (let [inum (atom 0)]
{:update (fn [f & args] (apply swap! inum f args))
:countup (fn [] (swap! inum inc))
:get (fn [] #inum)}))
user> (def inc-dec-map (assoc inc-map :countdown
(fn [] ((inc-map :update) dec))))
#'user/inc-dec-map
user> ((inc-dec-map :countup))
;;=> 1
user> ((inc-dec-map :countup))
;;=> 2
user> ((inc-dec-map :countdown))
;;=> 1
user> ((inc-dec-map :countdown))
;;=> 0
user> ((inc-dec-map :countdown))
;;=> -1
and then you can just seal it, dissoc'ing :update, (say if you make it publicly accessed to some other namespace.
otherwise you could provide an getter/updater to the ops object:
(def counter-ops (let [inum (atom 0)
ops (atom {:countup (fn [] (swap! inum inc))
:get (fn [] #inum)})]
(fn
;; get operations map snapshot
([] #ops)
;; get operation
([op] (-> ops deref op))
;; set operation
([op f & args] (swap! ops assoc op (fn [& args] (apply f inum args)))))))
user> (counter-ops :countdown (fn [inum] (swap! inum dec)))
user> (counter-ops :decrease-by (fn [inum n] (swap! inum - n)))
user> ((counter-ops :countdown))
;;=> -1
user> ((counter-ops :countdown))
;;=> -2
user> ((counter-ops :countup))
;;=> -1
user> ((counter-ops :countup))
;;=> 0
user> ((counter-ops :decrease-by) 10)
;;=> -10
seal it to be locked for any subsequent op additions:
user> (def counter-ops-sealed (counter-ops))
#'user/counter-ops-sealed
user> ((counter-ops-sealed :countup))
;;=> 2
user> ((counter-ops-sealed :countdown))
;;=> 1

Setting a debug function from the command line in Clojure

I have a namespace like this:
(ns foo.core)
(def ^:dynamic *debug-fn*
"A function taking arguments [bar baz]"
nil)
(defn bar-info
[bar _]
(println bar))
(defn baz-info
[_ baz]
(println baz))
(defn do-stuff
[bar baz]
(when *debug-fn* (*debug-fn* bar baz)))
(defn -main
[& {:keys [debug-fn]}]
(binding [*debug-fn* (symbol debug-fn)] ;; THIS WON'T WORK!
(do-stuff 27 42)))
What I would like to do is allow a debug function to be specified from the command line like this: lein run bar-info or lein run baz-info.
I'm not sure how to take the string specified as a command-line argument and turn it into the namespace-qualified function to bind. Do I need a macro to do this?
Use ns-resolve, you will need to specify namespace where your function is defined though.
user=> (defn f [n] (* n n n))
#'user/f
user=> ((ns-resolve *ns* (symbol "f")) 10)
1000
Use alter-var-root:
user=> (doc alter-var-root)
-------------------------
clojure.core/alter-var-root
([v f & args])
Atomically alters the root binding of var v by applying f to its
current value plus any args
nil
user=> (alter-var-root #'*debug-fn* (fn [v] (fn [x] (println x) x)))
#<user$eval171$fn__172$fn__173 user$eval171$fn__172$fn__173#7c93d88e>
user=> (*debug-fn* 1)
1
1
Though I've accepted Guillermo's answer above, I figured that it might also be useful to add the solution I ended up going with:
(def debug-fns
{:bar-info (fn [bar _] (println bar))
:baz-info (fn [_ baz] (println baz))
(def active-debug-fns (atom []))
(defn activate-debug-fn!
[fn-key]
(let [f (debug-fns fn-key)]
(if f
(swap! active-debug-fns conj f)
(warn (str "Debug function " fn-key " not found! Available functions are: "
(join " " (map name (keys debug-fns))))))))
(defn debug-fn-keys
[args]
(if (args "--debug")
(split (or (args "--debug") "") #",")
[]))
(defn do-stuff
[bar baz]
(doseq [f #active-debug-fns]
(f bar baz)))
(defn -main
[& args]
(let [args (apply hash-map args)]
(doseq [f (debug-fn-keys args)]
(activate-debug-fn! (keyword k)))
(do-stuff 27 42)))
So now you can say something like lein run --debug bar-info to get info on bars, or lein run --debug bar,baz to get info on both bars and bazes.
Any suggestions to make this more idiomatic will be happily accepted and edited in. :)

Clojure multimethod dispatching on functions and values

I have a function that returns the indexes in seq s at which value v exists:
(defn indexes-of [v s]
(map first (filter #(= v (last %)) (zipmap (range) s))))
What I'd like to do is extend this to apply any arbitrary function for the existence test. My idea is to use a multimethod, but I'm not sure exactly how to detect a function. I want to do this:
(defmulti indexes-of ???)
(defmethod indexes-of ??? [v s] ;; v is a function
(map first (filter v (zipmap (range) s))))
(defmethod indexes-of ??? [v s] ;; v is not a function
(indexes-of #(= v %) s))
Is a multimethod the way to go here? If so, how can I accomplish what I'm trying to do?
If you want to use a multimethod it should be on the filter function, which is the one changing according to the existence test type.
So
(defmulti filter-test (fn [value element]
(cond
(fn? value) :function
:else :value)))
(defmethod filter-test :function
[value element]
(apply value [element]))
(defmethod filter-test :value
[value element]
(= value element))
(defn indexes-of [v s]
(map first (filter #(filter-test v (last %)) (zipmap (range) s))))
Consider the JVM doesn't support first-class functions, or lambdas, out of the box, so there's no "function" data type to dispatch on, that's the reason the fn? test.
None the less the predicate solution proposed by noisesmith is the proper way to go in this situation IMO.
(defmulti indexes-of (fn [v _]
(if (fn? v)
:function
:value)))
(defmethod indexes-of :function
[f coll]
(keep-indexed (fn [i v] (when (f v) i)) coll))
(defmethod indexes-of :value
[v coll]
(indexes-of (partial = v) coll))
How about something simpler and more general:
(defn index-matches [predicate s]
(map first (filter (comp predicate second) (map vector (range) s))))
user> (index-matches even? (reverse (range 10)))
(1 3 5 7 9)
user> (index-matches #{3} [0 1 2 3 1 3 44 3 1 3])
(3 5 7 9)
thanks to a suggestion from lgrapenthin, this function is also now effective for lazy input:
user> (take 1 (index-matches #{300000} (range)))
(300000)

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))))

make sequence side-effectfull in Clojure

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)