I have the following code that works:
(def *primes*
(let [l "2 3 5 7 11 13 17 19 23 29 31"
f (fn [lst] (filter #(< 0 (count (str/trim %))) lst))
m (fn [lst] (map #(Integer/parseInt %) lst))]
(-> l
(str/partition #"[0-9]+")
f
m)))
If I change it to inline the filter (f) and map (m) functions to this:
(def *primes*
(let [l "2 3 5 7 11 13 17 19 23 29 31"]
(-> l
(str/partition #"[0-9]+")
(fn [lst] (filter #(< 0 (count (str/trim %))) lst))
(fn [lst] (map #(Integer/parseInt %) lst)))))
it doesn't compile anymore. The error is:
#<CompilerException java.lang.RuntimeException: java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.lang.Symbol (NO_SOURCE_FILE:227)>
Can anyone explain this to me?
The problem that I'm trying to solve is that map and filter takes the collection as the last parameter, yet str/partition takes the collection as the first, so I'm trying to mix the two using -> but currying map and filter into functions that only take one (the first) parameter for the collection to go into.
You can mix -> and ->> to a certain degree.
(-> l
(str/partition #"[0-9]+")
(->> (filter #(< 0 (count (str/trim %)))))
(->> (map #(Integer/parseInt %))))
But usually having problems like this is a sign that you try to do too much in one form. This simple example could be easily fixed.
(->> (str/partition l #"[0-9]+")
(filter #(< 0 (count (str/trim %))))
(map #(Integer/parseInt %)))
You're using function declarations as function calls. the immediate (ugly) way to fix it is to replace (fn [..] ..) with ((fn [..] ...))
-> is a macro. It manipulates the code you give it, and then executes that code. What happens when you try to use anonymous functions inline like that, is the previous expressions get threaded in as the first argument to fn. That is not what you want. You want them threaded in as the first argument to the actual function.
To use ->, you'd have to declare the functions beforehand, as you did in your first example.
Related
I often have to run my data through a function if the data fulfill certain criteria. Typically, both the function f and the criteria checker pred are parameterized to the data. For this reason, I find myself wishing for a higher-order if-then-else which knows neither f nor pred.
For example, assume I want to add 10 to all even integers in (range 5). Instead of
(map #(if (even? %) (+ % 10) %) (range 5))
I would prefer to have a helper –let's call it fork– and do this:
(map (fork even? #(+ % 10)) (range 5))
I could go ahead and implement fork as function. It would look like this:
(defn fork
([pred thenf elsef]
#(if (pred %) (thenf %) (elsef %)))
([pred thenf]
(fork pred thenf identity)))
Can this be done by elegantly combining core functions? Some nice chain of juxt / apply / some maybe?
Alternatively, do you know any Clojure library which implements the above (or similar)?
As Alan Thompson mentions, cond-> is a fairly standard way of implicitly getting the "else" part to be "return the value unchanged" these days. It doesn't really address your hope of being higher-order, though. I have another reason to dislike cond->: I think (and argued when cond-> was being invented) that it's a mistake for it to thread through each matching test, instead of just the first. It makes it impossible to use cond-> as an analogue to cond.
If you agree with me, you might try flatland.useful.fn/fix, or one of the other tools in that family, which we wrote years before cond->1.
to-fix is exactly your fork, except that it can handle multiple clauses and accepts constants as well as functions (for example, maybe you want to add 10 to other even numbers but replace 0 with 20):
(map (to-fix zero? 20, even? #(+ % 10)) xs)
It's easy to replicate the behavior of cond-> using fix, but not the other way around, which is why I argue that fix was the better design choice.
1 Apparently we're just a couple weeks away from the 10-year anniversary of the final version of fix. How time flies.
I agree that it could be very useful to have some kind of higher-order functional construct for this but I am not aware of any such construct. It is true that you could implement a higher order fork function, but its usefulness would be quite limited and can easily be achieved using if or the cond-> macro, as suggested in the other answers.
What comes to mind, however, are transducers. You could fairly easily implement a forking transducer that can be composed with other transducers to build powerful and concise sequence processing algorithms.
The implementation could look like this:
(defn forking [pred true-transducer false-transducer]
(fn [step]
(let [true-step (true-transducer step)
false-step (false-transducer step)]
(fn
([] (step))
([dst x] ((if (pred x) true-step false-step) dst x))
([dst] dst))))) ;; flushing not performed.
And this is how you would use it in your example:
(eduction (forking even?
(map #(+ 10 %))
identity)
(range 20))
;; => (10 1 12 3 14 5 16 7 18 9 20 11 22 13 24 15 26 17 28 19)
But it can also be composed with other transducers to build more complex sequence processing algorithms:
(into []
(comp (forking even?
(comp (drop 4)
(map #(+ 10 %)))
(comp (filter #(< 10 %))
(map #(vector % % %))
cat))
(partition-all 3))
(range 20))
;; => [[18 20 11] [11 11 22] [13 13 13] [24 15 15] [15 26 17] [17 17 28] [19 19 19]]
Another way to define fork (with three inputs) could be:
(defn fork [pred then else]
(comp
(partial apply apply)
(juxt (comp {true then, false else} pred) list)))
Notice that in this version the inputs and output can receive zero or more arguments. But let's take a more structured approach, defining some other useful combinators. Let's start by defining pick which corresponds to the categorical coproduct (sum) of morphisms:
(defn pick [actions]
(fn [[tag val]]
((actions tag) val)))
;alternatively
(defn pick [actions]
(comp
(partial apply apply)
(juxt (comp actions first) rest)))
E.g. (mapv (pick [inc dec]) [[0 1] [1 1]]) gives [2 0]. Using pick we can define switch which works like case:
(defn switch [test actions]
(comp
(pick actions)
(juxt test identity)))
E.g. (mapv (switch #(mod % 3) [inc dec -]) [3 4 5]) gives [4 3 -5]. Using switch we can easily define fork:
(defn fork [pred then else]
(switch pred {true then, false else}))
E.g. (mapv (fork even? inc dec) [0 1]) gives [1 0]. Finally, using fork let's also define fork* which receives zero or more predicate and action pairs and works like cond:
(defn fork* [& args]
(->> args
(partition 2)
reverse
(reduce
(fn [else [pred then]]
(fork pred then else))
identity)))
;equivalently
(defn fork* [& args]
(->> args
(partition 2)
(map (partial apply (partial partial fork)))
(apply comp)
(#(% identity))))
E.g. (mapv (fork* neg? -, even? inc) [-1 0 1]) gives [1 1 1].
Depending on the details, it is often easiest to accomplish this goal using the cond-> macro and friends:
(let [myfn (fn [val]
(cond-> val
(even? val) (+ val 10))) ]
with result
(mapv myfn (range 5)) => [10 1 14 3 18]
There is a variant in the Tupelo library that is sometimes helpful:
(mapv #(cond-it-> %
(even? it) (+ it 10))
(range 5))
that allows you to use the special symbol it as you thread the value through multiple stages.
As the examples show, you have the option to define and name the transformer function (my favorite), or use the function literal syntax #(...)
Firstly; sorry if the terminology I'm using is incorrect, I'm still very new to clojure and the paradigm shift is taking some time.
I am trying to work with a function which takes the first item from a set which is greater than twelve (is a 'teen' number). I can write this when I'm just applying it directly to a set, but I'm unsure how to write the function within a map. Can anyone point me in the right direction?
I tried a few things, typically along the lines of (partial (first (filter (partial < 12)))) but without any luck at all so far, and researching definitions of filter/partial has not yet proved fruitful.
TL/DR
I want to have, as a value in a map, a function which takes the first item in a list which is greater than 12.
(def test-set [1, 8, 15, 22, 29])
(def some-functions {
:first first
:last last
:teenth "I don't know what to put here"
})
(first (filter (partial < 12) test-set))
One way is to use an anonymous function when defining the map (https://riptutorial.com/clojure/example/15544/defining-anonymous-functions)
> (def some-functions {
:first first
:last last
:teenth #(first (filter (partial < 12) %))})
> ((:first some-functions) test-set)
1
> ((:last some-functions) test-set)
29
> ((:teenth some-functions) test-set)
15
Of course you could also have explicitly defined your function and used it in your map:
> (defn teenth [coll] (first (filter (partial < 12) coll)))
> (def some-functions {
:first first
:last last
:teenth teenth})
(As an aside, be careful with the word set. In clojure sets are unordered collections of unique values. https://clojure.org/reference/data_structures)
I found a small improvement to #jas' answer.
The functions
#(first (filter (partial < 12) %))
and
(defn teenth [coll] (first (filter (partial < 12) coll)))
use a combination of first and filter.
This is a use case for the some function as stated on clojuredocs.org [1].
I would propose to refactor the functions to
(fn [coll] (some #(if (< 12 %) %) coll))
and
(defn teenth [coll] (some #(if (< 12 %) %) coll))
Due to the slightly more complex predicate function #(if (< 12 %) %) we cannot use partial anymore.
Please be aware that you cannot create nested anonymous functions by using the reader macro #() [2]. In this case, you have to use fn to create the nested anonymous function as shown above.
Actually, you could use fn twice, but in my opinion it's not readable anymore:
(fn [coll] (some (fn [e] (if (< 12 e) e)) coll))
[1] https://clojuredocs.org/clojure.core/some#example-542692c6c026201cdc326940
[2] https://clojure.org/reference/reader#_dispatch
Create a lazy sequence by concatenating collections.
Consider the following function:
(defn req []
(Thread/sleep 1000)
(repeat 4 (rand-int 10)))
The sleep is added since the function will finally be a http request, thus it should emulate a delay.
Sample outputs:
(req)
;; (8 8 8 8)
(req)
;; (4 4 4 4)
I'm thinking of a function now, that creates a lazy sequence build by the concatenation of subsequent req results.
(take 10 (f req))
;; (3 3 3 3 2 2 2 2 9 9)
Here is one implementation:
(defn f [g]
(lazy-seq (concat (g) (f g))))
Is this the way to go? I'm somehow guessing that there might be already an abstraction for this available.. I tried lazy-cat, but this macro seems to work only for a fixed number of given sequences.
It turns out that this is a working abstraction:
(take 10 (apply concat (repeatedly req)))
However it looks like chunking of lazy sequences causes req to be called more often than needed here, which would not be acceptable if it's an http request.
The "unneeded" realizations of elements of lazy sequence is happening because apply needs to know the number of arguments that passed function is applied to.
Having a quick look at Clojure core lib, it seems, that it doesn't provide a function that concatenates a sequence of sequences and, at the same time, handles laziness in a way you want (doesn't redundantly realize the elements of passed lazy sequence), so, you'll need to implement it yourself.
Here's possible solution:
(defn apply-concat [xs]
(lazy-seq
(when-let [s (seq xs)]
(concat (first s) (apply-concat (rest s))))))
And then:
user> (defn req []
(println "--> making request")
[1 2 3 4])
#'user/req
user> (dorun (take 4 (apply-concat (repeatedly req))))
--> making request
nil
user> (dorun (take 5 (apply-concat (repeatedly req))))
--> making request
--> making request
nil
user> (dorun (take 8 (apply-concat (repeatedly req))))
--> making request
--> making request
nil
user> (dorun (take 9 (apply-concat (repeatedly req))))
--> making request
--> making request
--> making request
nil
The only concern with this approach is danger of blowing the stack, since apply-concat is potentially infinitely recursive.
Update:
To be precise apply realizes (arity of passed function + 1) elements of passed lazy sequence:
user> (dorun (take 1 (apply (fn [& xs] xs) (repeatedly req))))
--> making request
--> making request
nil
user> (dorun (take 1 (apply (fn [x & xs] xs) (repeatedly req))))
--> making request
--> making request
--> making request
nil
user> (dorun (take 1 (apply (fn [x y & xs] xs) (repeatedly req))))
--> making request
--> making request
--> making request
--> making request
nil
how about
(take 14
(mapcat identity (repeatedly req)))
explanation:
(defn req []
(print ".")
(repeat 4 (rand-int 10)))
(def x
(take 80 (mapcat identity (repeatedly req))))
; prints .... = 4x ; this is probably some repl eagerness
; to take 80 items, 20 realizatons (of 4 items) are requrend
(def y
(doall
(take 80 (mapcat identity (repeatedly req)))))
; prints ..................... = 21x
EDIT: about those 4 early realizations:
I think this is due apply, which us used by mapcat.
It realizes up to 4 args [^clojure.lang.IFn f a b c d & args] given multiple ones.
I am learning Clojure and trying to solve Project's Euler (http://projecteuler.net/) problems using this language.
Second problem asks to find the sum of the even-valued terms in Fibonacci sequence whose values do not exceed four million.
I've tried several approaches and would find next one most accurate if I could find where it's broken. Now it returns 0. I am pretty sure there is a problem with take-while condition but can't figure it out.
(reduce +
(take-while (and even? (partial < 4000000))
(map first (iterate (fn [[a b]] [b (+ a b)]) [0 1]))))
To compose multiple predicates in this way, you can use every-pred:
(every-pred even? (partial > 4000000))
The return value of this expression is a function that takes an argument and returns true if it is both even and greater than 4000000, false otherwise.
user> ((partial < 4000000) 1)
false
Partial puts the static arguments first and the free ones at the end, so it's building the opposite of what you want. It is essentially producing #(< 4000000 %) instead of #(< % 4000000) as you intended, So just change the > to <:
user> (reduce +
(take-while (and even? (partial > 4000000))
(map first (iterate (fn [[a b]] [b (+ a b)]) [0 1]))))
9227464
or perhaps it would be more clear to use the anonymous function form directly:
user> (reduce +
(take-while (and even? #(< % 4000000))
(map first (iterate (fn [[a b]] [b (+ a b)]) [0 1]))))
9227464
Now that we have covered a bit about partial, let's break down a working solution. I'll use the thread-last macro ->> to show each step separately.
user> (->> (iterate (fn [[a b]] [b (+ a b)]) [0 1]) ;; start with the fibs
(map first) ;; keep only the answer
(take-while #(< % 4000000)) ;; stop when they get too big
(filter even?) ;; take only the even? ones
(reduce +)) ;; sum it all together.
4613732
From this we can see that we don't actually want to compose the predicates evan? and less-than-4000000 on a take-while because this would stop as soon as either condition was true leaving only the number zero. Rather we want to use one of the predicates as a limit and the other as a filter.
I'm working through a book on clojure and ran into a stumbling block with "->>". The author provides an example of a comp that converts camelCased keywords into a clojure map with a more idiomatic camel-cased approach. Here's the code using comp:
(require '[clojure.string :as str])
(def camel->keyword (comp keyword
str/join
(partial interpose \-)
(partial map str/lower-case)
#(str/split % #"(?<=[a-z])(?=[A-Z])")))
This makes a lot of sense, but I don't really like using partial all over the place to handle a variable number of arguments. Instead, an alternative is provided here:
(defn camel->keyword
[s]
(->> (str/split s #"(?<=[a-z])(?=[A-Z])")
(map str/lower-case)
(interpose \-)
str/join
keyword))
This syntax is much more readable, and mimics the way I would think about solving a problem (front to back, instead of back to front). Extending the comp to complete the aforementioned goal...
(def camel-pairs->map (comp (partial apply hash-map)
(partial map-indexed (fn [i x]
(if (odd? i)
x
(camel->keyword x))))))
What would be the equivalent using ->>? I'm not exactly sure how to thread map-indexed (or any iterative function) using ->>. This is wrong:
(defn camel-pairs->map
[s]
(->> (map-indexed (fn [i x]
(if (odd? i)
x
(camel-keyword x)))
(apply hash-map)))
Three problems: missing a parenthesis, missing the > in the name of camel->keyword, and not "seeding" your ->> macro with the initial expression s.
(defn camel-pairs->map [s]
(->> s
(map-indexed
(fn [i x]
(if (odd? i)
x
(camel->keyword x))))
(apply hash-map)))
Is this really more clear than say?
(defn camel-pairs->map [s]
(into {}
(for [[k v] (partition 2 s)]
[(camel->keyword k) v])))