Making Clojure let statement more functional - clojure

In my first Clojure project everything turned out nicely except this part at the end:
(let [broken-signs (->> (:symbols field)
(map make-sign)
(filter broken?))
broken-count (count broken-signs)
unfixable-count (-> (filter (complement fixable?) broken-signs)
(count))]
(println
(if (> unfixable-count 0)
-1
(- broken-count unfixable-count))))
The indentation looks off and it does not feel functional, since I am reusing state in the let block. I basically count the number of broken signs and then the number of fixable signs. If any sign is unfixable, I print -1, otherwise I print the number of signs to be fixed.
If I mapped/filtered twice, I'd have duplicate code, but most of all it'd run slower. Is there a way of improving this code nevertheless?
EDIT: This is what I settled on
(defn count-broken-yet-fixable []
(let [broken (->> (:symbols field)
(map make-sign)
(filter broken?))
unfixable (remove fixable? broken)]
(when (empty? unfixable)
(count broken))))
(defn solve-task []
(if-let [result (count-broken-yet-fixable)]
result
-1))
(println (solve-task))
The subtraction was indeed not necessary and the count did not have to happen in the let block. Outputting the -1 on bad input also isn't the job of the function and is only part of the task.

I don't think there's anything "non-functional" or wrong with your approach. The indentation looks fine.
(let [broken (->> (:symbols field)
(map make-sign)
(filter broken?))
unfixable (remove fixable? broken)]
(when (seq unfixable)
(- (count broken) (count unfixable))))
You could replace filter (complement with remove
Could use pos? instead of (> n 0)
I might put two printlns inside the if, but really it's better to return a value
You could inline the broken-count binding, since it's only used in one place
I personally think this is easier to read with less threading macros
Since the need to count unfixables is conditional, you could test for values with seq first
If you return -1 as a sentinel value, I'd use nil instead; this happens naturally when the when condition isn't met
The conditional logic seems backwards: you return -1 when unfixable-count is positive, and only use its value when it's not positive (which means it's zero b/c count can't be negative), e.g. it could be rewritten as (- broken-count 0) and then just broken-count

(let [broken-signs (->> (:symbols field)
(map make-sign)
(filter broken?))]
(if-let [unfixable-signs (seq (remove fixable? broken-signs))]
-1
(- (count broken-signs) (count unfixable-signs)))
Your code is already pretty neat and well laid out. The only change I would want to do, is stay in the domain as long as possible - in this case the signs objects. And use the counts only much later.
The return value can then use print to do the actual actions.

Your code doesn't have side-effects (except for printing, which we'll fix), so I wouldn't say it's not functional. let is designed for building up intermediate values. In comments are some potential improvements.
; align here (controversial)
(let [broken-signs (->> (:symbols field)
(map make-sign)
(filter broken?))
broken-count (count broken-signs)
unfixable-count (->> broken-signs ; maybe emphasize non-function start
(filter (complement fixable?))
count)] ; no parens needed
;; don't print; just return number
(if (< 0 unfixable-count) ; prefer less-than (Elements of Clojure book)
-1
(- broken-count unfixable-count)))
I highly recommend the Clojure Style Guide for related suggestions.

Related

Using partials within function as value on a map

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

Idiomatic and lazy eventually truthy in a list in Clojure

I'd like to have a function/macro for checking a list to have truthy value eventually, and I hope the evaluation would be lazy. Here is my illustrative implementation without lazy evaluation:
(defn eventual [cols]
(or (first cols) (if-let [rs (rest cols)]
(eventual rs))
false))
Here is a trivial example to illustrate:
(if (eventual [false (+ 1 2) (* 10000 10000)])
true
false)
I feel that there must be an implication with lazy evaluation. Maybe I'm just blinded at the moment. Please help to help. Thanks
You can check if a sequence contains at least one truthy element with some function:
(some identity col)
If you pass it a lazy sequence as col it will evaluate its contents up to the first truthy element and won't realise the rest:
(let [col (take
10
(iterate
#(do (println "Generating new value from " %) (inc %))
0))]
(some #(> % 5) col))
produces:
Generating new value from 0
Generating new value from 1
Generating new value from 2
Generating new value from 3
Generating new value from 4
Generating new value from 5
true
As you can see, values 6..9 are not produces at all.
You also should double check that the col you pass to some is really lazy and not already realised, because it might confuse you.
Your eventual function is as lazy as it can be. It searches eagerly for the first truthy item then stops. But it has problems:
It fails to terminate on an empty collection. (rest ()) is (),
which is truthy. Use next instead of rest. (next ()) is nil,
which is falsy.
It is truly recursive. It will blow the stack on a long enough
search. Try (eventual (repeat false)). Since the recursion is
tail-recursion, you can fix this by using recur in its place.
While we are at it, it is idiomatic to return nil, not false,
upon running out of a collection. So drop the final false.
We end up with
(defn eventual [cols]
(or (first cols) (if-let [rs (next cols)]
(recur rs))))
I'm a little queasy about what happens if cols is empty. Code based upon the source for some is clearer:
(defn eventual [coll]
(when (seq coll)
(or (first coll) (recur next coll))))
But using (some identity col), as Piotrek suggests, is probably best.

change values from global variable in Clojure

I'm a total beginer in Clojure and I've ran into a problem that I'm not even sure if can be done in Closure.
So the issue is the following. I've implemented a function that computes the prime numbers from an interval (up to a limit).
(defn gather_primes_in_range [range_start range_end target_number prime_list]
(if (or (= 0 target_number) (> range_start range_end) (= FIND_MORE_PRIMES false))
prime_list
(do
(if (is_prime? range_start)
(gather_primes_in_range (+ range_start 1) range_end (- target_number 1) (conj, prime_list, range_start))
(gather_primes_in_range (+ range_start 1) range_end target_number prime_list)
)
)
)
)
(defn find_nr_of_primes_in_range [range_start range_end target_number]
(if (< range_start 2)
(gather_primes_in_range 2 range_end target_number [])
(gather_primes_in_range range_start range_end target_number [])
)
)
This works just fine. But what I want now is to have a global variable that should store on each method call the primes that are found in a variable to lookup later. In other languages like Python, Ruby or Scala I would just do this by having a Set to which I add entries before returing from the function. But in Clojure I have no ideea how to go around this.
Basically what I tried is, have somewhere global declared:
(def PRIMES_FOUND_SO_FAR #{})
And then somehow on return add the entries to this variable. Is this possible at all in Clojure and if so how? I've tried on other variables to change their values using either swap! and atom, or set! but could not make it to work here in any situation.
Firstly, I strongly advice you to read about clojure code conventions What are Clojure's Naming Conventions?
Let me show you some improvements of your code.
1) Applying clojure naming conventions.
Then switch from (+ variable 1) to (inc variable) (the same optimizations with dec).
Also (= FIND_MORE_PRIMES false) can be simply replaced by find-more-primes?
And finally the condition (= 0 smthng) could be written in more idiomatic style (zero? smthng)
Now your code looks a bit more readable:
(defn gather-primes-in-range [range-start range-end target-number prime-list]
(if (or (zero? target-number) (> range-start range-end) need-more-primes?)
prime-list
(do
(if (is-prime? range-start)
(gather-primes-in-range (inc range-start) range-end (dec target-number) (conj prime-list range-start))
(gather-primes-in-range (inc range-start) range-end target-number prime-list)))))
2) Now we should remove redundant do call cause it wraps the only one function call.
And the last trick is to apply tail recursion (http://clojure.org/special_forms#Special%20Forms--(recur%20exprs*)) via swapping entire gather-primes-in-range calls to recur
(defn gather-primes-in-range
[range-start range-end target-number prime-list]
(if (or (zero? target-number) (> range-start range-end) need-more-primes?)
prime-list
(if (is-prime? range-start)
(recur (inc range-start) range-end (dec target-number) (conj prime-list range-start))
(recur (inc range-start) range-end target-number prime-list))))
And here comes time for answering your question. You wouldn't benefit from this approach
(def PRIMES_FOUND_SO_FAR #{})
because you haven't opportunity to change this set. The only thing that you can deal with it is to create some new immutable data structure from that one.
As #georgek mention you could simply use atom in this particular case.
(def PRIMES_FOUND_SO_FAR (atom #{}))
Adding new prime number to atom:
(swap! PRIMES_FOUND_SO_FAR conj prime-number)
Deref atom for extracting the value:
#PRIMES_FOUND_SO_FAR ;; or (deref PRIMES_FOUND_SO_FAR)
-> #{2 3 5 7 11}
Anyway your code is a little bit imperative but you should always remember that clojure is functional language with immutable data structures, functions as arguments, etc. using global variables is not good idea at all. BTW thats how your function should look like in clojure style:
(defn gather-primes-in-range [start end target-number]
(take target-number (filter is-prime? (range start end))))
for those who have spent too much time searching how to modify a global (root) variable in clojure here is the solution:
(def user-remote-browser "anonymous")
you can modify it from anywhere i suppose but in the same namepace with:
(alter-var-root #'user-remote-browser (constantly name))
alter-var-root use a function to modify a variable,
constantly create a constant function returning here the string name

Clojure :: get the single element of a list and throw exception if the list has more than 1 elements

I know at a certain point in my code that a list only has one element so I obtain it with
(first alist)
But I would also like the code to break if the list has more than one elements to alert me of the erroneous condition. What's an idiomatic way to achieve that in Clojure ?
Replace first with an only (or other poetically named) function with a pre-condition where you want to make your assertion:
(defn only [x] {:pre [(nil? (next x))]} (first x))
(only [1])
=> 1
(only [1 2])
=> AssertionError Assert failed: (nil? (next x)) user/only (NO_SOURCE_FILE:1)
This will blow up on a collection with anything other than one element. Works fine on lazy seqs as well.
(defn only
"Gives the sole element of a sequence"
[coll]
(if (seq (rest coll))
(throw (RuntimeException. "should have precisely one item, but had at least 2"))
(if (seq coll)
(first coll)
(throw (RuntimeException. "should have precisely one item, but had 0")))))
I can't immediately think of a nice concise, idiomatic way to do this.
Option 1 is that there isn't one, because this is a bit of an odd situation. If you know there's supposed to be exactly one element, why is it in a list in the first place?
Option 2 is that there is one, and someone will come along and tell off for not seeing it :)
That said, in your situation I'd probably write something like:
(let [[item & rest] alist]
(if (nil? rest)
(throw (IllegalArgumentException. "Expected a single-element list"))
item))
Possibly more simply, you could also just do (count alist) and make sure it had exactly one item. The code above, though, has the nice property that it won't force evaluation beyond the head of the list, but depending on your use case that might not be a concern.
The Tupelo library has this function defined as a core sanity-check, allowing one to "unwrap" scalar values from length-1 vectors/lists and document the intended result. The definition is simplicity itself:
(defn only
"(only coll)
Ensures that a sequence is of length=1, and returns the only value present.
Throws an exception if the length of the sequence is not one.
Note that, for a length-1 sequence S, (first S), (last S) and (only S) are equivalent."
[coll]
(let [coll-seq (seq coll)
num-items (count coll-seq)]
(when-not (= 1 num-items)
(throw (IllegalArgumentException. (str "only: num-items must=1; num-items=" num-items))))
(clojure.core/first coll-seq)))
You can find a similar function in the SuchWow library and other places.

I have two versions of a function to count leading hash(#) characters, which is better?

I wrote a piece of code to count the leading hash(#) character of a line, which is much like a heading line in Markdown
### Line one -> return 3
######## Line two -> return 6 (Only care about the first 6 characters.
Version 1
(defn
count-leading-hash
[line]
(let [cnt (count (take-while #(= % \#) line))]
(if (> cnt 6) 6 cnt)))
Version 2
(defn
count-leading-hash
[line]
(loop [cnt 0]
(if (and (= (.charAt line cnt) \#) (< cnt 6))
(recur (inc cnt))
cnt)))
I used time to measure both tow implementations, found that the first version based on take-while is 2x faster than version 2. Taken "###### Line one" as input, version 1 took 0.09 msecs, version 2 took about 0.19 msecs.
Question 1. Is it recur that slows down the second implementation?
Question 2. Version 1 is closer to functional programming paradigm , is it?
Question 3. Which one do you prefer? Why? (You're welcome to write your own implementation.)
--Update--
After reading the doc of cloujure, I came up with a new version of this function, and I think it's much clear.
(defn
count-leading-hash
[line]
(->> line (take 6) (take-while #(= \# %)) count))
IMO it isn't useful to take time measurements for small pieces of code
Yes, version 1 is more functional
I prefer version 1 because it is easier to spot errors
I prefer version 1 because it is less code, thus less cost to maintain.
I would write the function like this:
(defn count-leading-hash [line]
(count (take-while #{\#} (take 6 line))))
No, it's the reflection used to invoke .charAt. Call (set! *warn-on-reflection* true) before creating the function, and you'll see the warning.
Insofar as it uses HOFs, sure.
The first, though (if (> cnt 6) 6 cnt) is better written as (min 6 cnt).
1: No. recur is pretty fast. For every function you call, there is a bit of overhead and "noise" from the VM: the REPL needs to parse and evaluate your call for example, or some garbage collection might happen. That's why benchmarks on such tiny bits of code don't mean anything.
Compare with:
(defn
count-leading-hash
[line]
(let [cnt (count (take-while #(= % \#) line))]
(if (> cnt 6) 6 cnt)))
(defn
count-leading-hash2
[line]
(loop [cnt 0]
(if (and (= (.charAt line cnt) \#) (< cnt 6))
(recur (inc cnt))
cnt)))
(def lines ["### Line one" "######## Line two"])
(time (dorun (repeatedly 10000 #(dorun (map count-leading-hash lines)))))
;; "Elapsed time: 620.628 msecs"
;; => nil
(time (dorun (repeatedly 10000 #(dorun (map count-leading-hash2 lines)))))
;; "Elapsed time: 592.721 msecs"
;; => nil
No significant difference.
2: Using loop/recur is not idiomatic in this instance; it's best to use it only when you really need it and use other available functions when you can. There are many useful functions that operate on collections/sequences; check ClojureDocs for a reference and examples. In my experience, people with imperative programming skills who are new to functional programming use loop/recur a lot more than those who have a lot of Clojure experience; loop/recur can be a code smell.
3: I like the first version better. There are lots of different approaches:
;; more expensive, because it iterates n times, where n is the number of #'s
(defn count-leading-hash [line]
(min 6 (count (take-while #(= \# %) line))))
;; takes only at most 6 characters from line, so less expensive
(defn count-leading-hash [line]
(count (take-while #(= \# %) (take 6 line))))
;; instead of an anonymous function, you can use `partial`
(defn count-leading-hash [line]
(count (take-while (partial = \#) (take 6 line))))
edit:
How to decide when to use partial vs an anonymous function?
In terms of performance it doesn't matter, because (partial = \#) evaluates to (fn [& args] (apply = \# args)). #(= \# %) translates to (fn [arg] (= \# arg)). Both are very similar, but partial gives you a function that accepts an arbitrary number of arguments, so in situations where you need it, that's the way to go. partial is the λ (lambda) in lambda calculus. I'd say, use what's easier to read, or partial if you need a function with an arbitrary number of arguments.
Micro-benchmarks on the JVM are almost always misleading, unless you really know what you're doing. So, I wouldn't put too much weight on the relative performance of your two solutions.
The first solution is more idiomatic. You only really see explicit loop/recur in Clojure code when it's the only reasonable alternative. In this case, clearly, there is a reasonable alternative.
Another option, if you're comfortable with regular expressions:
(defn count-leading-hash [line]
(count (or (re-find #"^#{1,6}" line) "")))