How to evaluate sequence of pure functions in Clojure - clojure

My question is pretty similar to this one: How to evaluate a sequence of impure functions in Clojure? but instead of impure functions, how can I evaluate sequence of pure functions and get the results as another sequence?
Let's assume we have a vector of functions like:
[#(str "a" "b") #(str "c" "d") #(str "e" "f")]
And we need an output like this:
("ab" "cd" "ef")
I've tried something similar to this:
(map eval [#(str "a" "b") #(str "c" "d") #(str "e" "f")])
but it just returns a vector of function references.

There are multiple ways to do what you are asking. It depends on whether you want a lazy sequence or not (you probably want lazy given there are no side-effects, but you might want no-lazy if there's an intensive computation that you want to cache), or if you want a vector as output (the same as your input). I'll try to follow what you tried to do.
Your map with eval is doing the following with each fn:
user=> (eval #(str 1))
#<user$eval1332$fn__1333 user$eval1332$fn__1333#38747597>
But you want something like the following:
user=> (eval (#(str 1)))
"1"
You want eval to have the fn applied, that is: the fn should be the first element of a list. Let's put it in a list:
user=> (map (comp eval list) [#(str "a" "b") #(str "c" "d") #(str "e" "f")])
("ab" "cd" "ef")
Cool. But instead of eval, you probably want to use apply:
user=> (apply #(str 1))
; ArityException Wrong number of args (1)
Ups! It failed. apply doesn't have a 0-arity overload, but we can pass an empty list:
user=> (apply #(str 1) ())
"1"
Much better. Let's do it with map:
user=> (map #(apply % ()) [#(str "a" "b") #(str "c" "d") #(str "e" "f")])
("ab" "cd" "ef")
Or better yet, given your functions receive no arguments, you'd better do as suggested by #Magos:
user=> (map #(%) [#(str "a" "b") #(str "c" "d") #(str "e" "f")])
("ab" "cd" "ef")

You could use (fn [f] (f)) or #(%) in your map.

eval evaluates a Clojure form (i.e., a list containing "code"). You have functions, not forms.
You map with apply, but apply takes both a function and a seq of arguments. Since you have no arguments, you can use the empty vector:
(map apply
[#(str "a" "b") #(str "c" "d") #(str "e" "f")]
(repeat []))
But it would be shorter and probably clearer if you use for:
(for [f [#(str "a" "b") #(str "c" "d") #(str "e" "f")]]
(f))

Note
As Nathan Davis wrote, eval evaluates a clojure form:
(eval '(+ 1 1)) ;=> 2
What does it do to a function? Nothing!. eval treats functions as literals:
((eval +) 1 1) ;=> 2
For your case:
(def stuff [#(str "a" "b") #(str "c" "d") #(str "e" "f")])
... we have
(= stuff (map eval stuff)) ;=> true
Though
(= [#(str "a" "b") #(str "c" "d") #(str "e" "f")]
(map eval [#(str "a" "b") #(str "c" "d") #(str "e" "f")]))
;=> false
... since the corresponding functions are different objects, though identical in operation.
That's why eval is useless to you. So follow Magos's advice.

Maybe it's worth to have a look at pcalls and/or pvalues
(pcalls #(str "a" "b") #(str "c" "d") #(str "e" "f"))
;=> ("ab" "cd" "ef")
Please note that pcalls is using future inside!

Related

clojure: Next element of an item that can fallback to first

I'd like to create a getnext fn that looks for a element in a coll and when match, return the next element. Also, it should return the first element if the last one is passed as argument.
(def coll ["a" "b" "c" "d"])
(defn get-next [coll item] ...)
(get-next coll "a") ;;=> "b"
(get-next coll "b") ;;=> "c"
(get-next coll "c") ;;=> "d"
(get-next coll "d") ;;=> "a" ; back to the beginning
Thanks!
How about this:
Append first item at the end of the sequence (lazily),
Drop non-items,
Return what's left (nil if item not found).
Or in code:
(defn get-next [coll item]
(->> (concat coll [(first coll)])
(drop-while (partial not= item))
second))
There are certainly purer lisp approaches than this one but, hey, as long as we got .indexOf, we might as well use it. The key to simplicity is that, plus cycle, so we don't have to check for the last item.
(defn get-next [coll item]
(nth (cycle coll) (inc (.indexOf coll item))))
Some test runs:
(get-next ["A" "B" "C" "D"] "B")
=> "C"
(get-next ["A" "B" "C" "D"] "D")
=> "A"
(get-next ["A" "B" "C" "D"] "E")
=> "A"
Whoops! Well, we didn't specify what we wanted to do if the item wasn't in the collection. Idiomatically, we would return nil, so we need a new get-next:
(defn get-next-2 [coll item]
(let [i (.indexOf coll item)]
(if (= -1 i) nil (nth (cycle coll) (inc i)))))
And now we catch the not-there case:
(get-next-2 ["A" "B" "C" "D"] "Q")
=> nil
I would convert coll to map and use it for lookups:
(def doll (zipmap coll (rest (cycle coll))))
(doll "a") => "b"
(doll "b") => "c"
(doll "d") => "a"
This is a good job for drop-while:
(defn get-next
[coll item]
(let [remainder (drop-while #(not= % item) coll)]
(when (empty? remainder)
(throw (IllegalArgumentException. (str "Item not found: " item))))
(if (< 1 (count remainder))
(nth remainder 1)
(first coll))))
(dotest
(let [coll [1 2 3 4]]
(is= 2 (get-next coll 1))
(is= 3 (get-next coll 2))
(is= 4 (get-next coll 3))
(is= 1 (get-next coll 4))
(throws? (get-next coll 5))))

How to instantiate a Stream.Builder class in clojure? (using java 9)

I'm following this example to initiate a Stream.Builder:
http://www.java2s.com/Tutorials/Java/java.util.stream/Stream.Builder/Stream.Builder.build_.htm
(def b (doto (Stream/builder)
(.accept "a")
(.accept "b")
(.accept "c")
(.accept "d")
(.accept "e")))
However, I'm getting this:
Unhandled java.lang.IncompatibleClassChangeError
Method
java.util.stream.Stream.builder()Ljava/util/stream/Stream$Builder;
must be InterfaceMethodref constant
Is there anything I'm missing?
quick research led me to this issue:
https://dev.clojure.org/jira/browse/CLJ-2284
so the workaround is as mentioned there:
(import 'java.util.stream.Stream)
(defmacro interface-static-call
[sym & argtypes]
`(let [m# (.getMethod ~(symbol (namespace sym))
~(name sym)
(into-array Class ~argtypes))]
(fn [& args#]
(.invoke m# nil (to-array args#)))))
(doto ((interface-static-call Stream/builder))
(.accept "a")
(.accept "b")
(.accept "c")
(.accept "d")
(.accept "e"))
;;=> #object[java.util.stream.Streams$StreamBuilderImpl 0x121300ed "java.util.stream.Streams$StreamBuilderImpl#121300ed"]
works for me on java 9
so i guess we should wait for a fix in clojure.
Very helpful, thanks, for those of us stuck on Clojure 8 but needing to use a Java newer than 1.8.
For what it's worth, the macro in the answer above won't work if argtypes is not empty, because the macro as written constructs an unquoted list of classes as the third parameter to .getMethod, and Clojure tries to invoke the first class in the list as an IFn. I needed to redefine the macro as:
(defmacro interface-static-call
[sym & argtypes]
`(let [m# (.getMethod ~(symbol (namespace sym))
~(name sym)
(into-array Class ~(into [] argtypes)))]
(fn [& args#]
(.invoke m# nil (to-array args#)))))

map-indexed function on arbitrary number of collections

There is a map-indexed function in Clojure, however (as of version "1.8.0"), it only accepts up to two arguments (source):
As I could not see any reason not to have an arbitrary number of arguments, I am trying to write my own version (reusing the existing map-indexed function) :
(defn map-index
"like clojure.core/map-indexed but accepts more than two arguments"
([f] ;;(partial (map f (range))) ;; TODO transducer ?
)
([f coll] (map f (range) coll))
([f c1 c2] (map f (range) c1 c2))
([f c1 c2 c3] (map f (range) c1 c2 c3))
([f c1 c2 c3 & colls]
;; Warning !
;; calling map-indexed with a final parameter freezes my REPL
(map f (conj colls c3 c2 c1 (range)))))
((map-indexed list) ["a" "b" "c"])
(map-indexed list ["a" "b" "c"])
((map-index list) ["a" "b" "c"]) ;; KO
(map-index list ["a" "b" "c"])
(map-index list ["a" "b" "c"] ["d" "e" "f"]) ;; OK
(map-index list ["a" "b" "c"] ["d" "e" "f"] ["g" "h" "i"]) ;; OK
(map-index list ["a" "b" "c"] ["d" "e" "f"] ["g" "h" "i"] ["k" "l" "m"]) ;; freezes the REPL
How should I write this map-index function ?
I would just write it like this:
(defn map-index
([f]
(map-indexed f))
([f & colls]
(apply map f (range) colls)))
Unless you really care about performance, there's no need to overcomplicate things with extra arities.
It's worth noting that since the transducer version here simply calls map-indexed, it won't work for an arbitrary number of collections. I'll leave it up to you to implement that if you need to do so.

vector in clojure and type casting

(= ":bar:foo" ((fn [[a b]] (str b a)) [:foo :bar]))
I have several question about this clojure code.
what's the deal about : in front each element in vector?
How can str cast :foo to string type ":foo" ?
Thanks
In clojure, such element called as keywords. Keywords evaluate to themselves, and often used as accessors for the values.
(def x {:a 10, :b 20})
You can check the type:
user=> (class :foo)
clojure.lang.Keyword
user=> (type :foo)
clojure.lang.Keyword
You can convert it to str: Be cautious that : in the front.
user=> (str :foo)
":foo"
If you want to get only the name string from the keyword, then:
user=> (name :foo)
"foo"
Or you can create a keyword from str:
user=> (keyword "foo")
:foo

Simple comparator does not sort as (I) expected

I expected this code snippet to produce the original vector, but sorted in a case-insensitive way. Instead I get the original vector untouched. Why doesn't my comparator work?
user=> (ns user (require [clojure.contrib.string :as str]))
nil
user=> (sort
(comparator #(compare (str/upper-case %1) (str/upper-case %2)))
["B" "a" "c" "F" "r" "E"])
("B" "a" "c" "F" "r" "E")
comparator returns a java.util.Comparator when given a predicate (a function which returns true or false). You don't need it if you're using compare explicitly. So just:
(sort #(compare (str/upper-case %1) (str/upper-case %2))
["B" "a" "c" "F" "r" "E"])
;=> ("a" "B" "c" "E" "F" "r")
Alternatively, use sort-by:
(sort-by str/upper-case ["B" "a" "c" "F" "r" "E"])
;=> ("a" "B" "c" "E" "F" "r")
compare is not a predicate, it's a comparator.