Function composition in Clojure? - clojure

Can Clojure implement (g ∘ f) constructions like Haskell's g . f? I'm currently using workarounds like (fn [n] (not (zero? n))), which isn't nearly as nice :)

There is a function to do this in clojure.core called comp. E.g.
((comp not zero?) 5)
; => true
You might also want to consider using -> / ->>, e.g.
(-> 5 zero? not)
; => true

You can use Clojure's reader-macro shortcut for anonymous functions to rewrite your version in fewer keystrokes.
user=> (#(not (zero? %)) 1)
true
For the specific case of composing not and another function, you can use complement.
user=> ((complement zero?) 1)
true
Using not in combination with when and if is common enough that if-not and when-not are core functions.
user=> (if-not (zero? 1) :nonzero :zero)
:nonzero

Another way is (reduce #(%2 %1) n [zero? not]) but I like (comp not zero?), already mentioned by Michal, better.

Related

Conditional "assignment" in functional programming

I am programming something that doesn't have side-effects, but my code is not very readable.
Consider the following piece of code:
(let [csv_data (if header_row (cons header_row data_rows) data_rows)]
)
I'm trying to use csv_data in a block of code. What is a clean way of conditioning on the presence of a header_row? I've looked at if-let, but couldn't see how that could help here.
I have run into similar situations with functional for-loops as well where I'm binding the result to a local variable, and the code looks like a pile of expressions.
Do I really have to create a separate helper function in so many cases?
What am I missing here?
Use the cond->> macro
(let [csv_data (cond->> data_rows
header_row (cons header-row)]
)
It works like the regular ->> macro, but before each threading form a test expression has to be placed that determines whether the threading form will be used.
There is also cond->. Read more about threading macros here: Official threading macros guide
First, don't use underscore, prefer dashes.
Second, there is nothing wrong with a little helper function; after all, this seems to be a requirement for handling your particular data format.
Third, if you can change your data so that you can skip those decisions and have a uniform representation for all corner cases, this is even better. A header row contains a different kind of data (column names?), so you might prefer to keep them separate:
(let [csv {:header header :rows rows}]
...)
Or maybe at some point you could have "headers" and "rows" be of the same type: sequences of rows. Then you can concat them directly.
The ensure-x idiom is a very common way to normalize your data:
(defn ensure-list [data]
(and data (list data)))
For example:
user=> (ensure-list "something")
("something")
user=> (ensure-list ())
(())
user=> (ensure-list nil)
nil
And thus:
(let [csv (concat (ensure-list header) rows)]
...)
i would propose an utility macro. Something like this:
(defmacro update-when [check val-to-update f & params]
`(if-let [x# ~check]
(~f x# ~val-to-update ~#params)
~val-to-update))
user> (let [header-row :header
data-rows [:data1 :data2]]
(let [csv-data (update-when header-row data-rows cons)]
csv-data))
;;=> (:header :data1 :data2)
user> (let [header-row nil
data-rows [:data1 :data2]]
(let [csv-data (update-when header-row data-rows cons)]
csv-data))
;;=> [:data1 :data2]
it is quite universal, and lets you fulfill more complex tasks then just simple consing. Like for example you want to reverse some coll if check is trueish, and concat another list...
user> (let [header-row :header
data-rows [:data1 :data2]]
(let [csv-data (update-when header-row data-rows
(fn [h d & params] (apply concat (reverse d) params))
[1 2 3] ['a 'b 'c])]
csv-data))
;;=> (:data2 :data1 1 2 3 a b c)
update
as noticed by #amalloy , this macro should be a function:
(defn update-when [check val-to-update f & params]
(if check
(apply f check val-to-update params)
val-to-update))
After thinking about the "cost" of a one-line helper function in the namespace I've came up with a local function instead:
(let [merge_header_fn (fn [header_row data_rows]
(if header_row
(cons header_row data_rows)
data_rows))
csv_data (merge_header_fn header_row data_rows) ]
...
<use csv_data>
...
)
Unless someone can suggest a more elegant way of handling this, I will keep this as an answer.

Clojure: pass value if it passes predicate truth test

Is it possible to remove the let statement / avoid the intermediate 'x' in the following code?:
(let [x (f a)]
(when (pred? x) x))
I bumped into this problem in the following use case:
(let [coll (get-collection-somewhere)]
(when (every? some? coll) ; if the collection doesn't contain nil values
(remove true? coll))) ; remove all true values
So if the collection is free of nil values, only not-true values remain, like numbers, strings, or whatever.
So, I'm looking for something like this:
(defn pass-if-true [x pred?]
(when (pred? x) x))
Assuming that you don't want to define that pass-if-true function, the best you can do is an anonymous function:
(#(when (every? some? %)
(remove true? %))
(get-collection-somewhere))
You could also extract the predicate and transformation into parameters:
(#(when (%1 %3) (%2 %3))
(partial every? some?)
(partial remove true?)
(get-collection-somewhere))
The let form is necessary to prevent your collection-building function from running twice:
(f a) or (get-collection-somewhere)
This is a typical idiom and you are doing it correctly.
Of course, you don't need the let if you already have the collection and are not building inside this expression.
However, you may wish to see when-let:
https://clojuredocs.org/clojure.core/when-let
It can save some keystrokes in some circumstances, but this isn't one of them.

Is it possible to use Clojure's case form with a Java enum?

The case doc says
Unlike cond and condp, case does a constant-time dispatch... All manner of constant
expressions are acceptable in case.
I would like to benefit from case's constant-time dispatch to match on Java enums. Java's switch statement works well with enums, but doing the following in Clojure:
(defn foo [x]
(case x
java.util.concurrent.TimeUnit/MILLISECONDS "yes!"))
(foo java.util.concurrent.TimeUnit/MILLISECONDS)
Results in: IllegalArgumentException No matching clause: MILLISECONDS
Are enums not supported in case? Am I doing something wrong? Must I resort to cond or is there a better solution?
The problem here is that case's test constants, as described in the docs, " must be compile-time literals". So, rather than resolving java.util.concurrent.TimeUnit/MILLISECONDS, the literal symbol 'java.util.concurrent.TimeUnit/MILLISECONDS is being tested against.
(foo java.util.concurrent.TimeUnit/MILLISECONDS) ; IllegalArgumentException
(foo 'java.util.concurrent.TimeUnit/MILLISECONDS) ; yes!
Instead, the solution is to dispatch on the .ordinal of the Enum instance, which is what Java itself does when compiling switch statements over enums:
(defn foo [x]
(case (.ordinal x)
2 "yes!"))
You can wrap this pattern in a macro which correctly evaluates the case ordinals for you:
(defmacro case-enum
"Like `case`, but explicitly dispatch on Java enum ordinals."
[e & clauses]
(letfn [(enum-ordinal [e] `(let [^Enum e# ~e] (.ordinal e#)))]
`(case ~(enum-ordinal e)
~#(concat
(mapcat (fn [[test result]]
[(eval (enum-ordinal test)) result])
(partition 2 clauses))
(when (odd? (count clauses))
(list (last clauses)))))))
You could use use a cond on the name of the enumm
(case (.name myEnumValue)
"NAME_MY_ENUM" (println "Hey, it works!"))
Seems to me very simple compared to the alternatives
Here's a simpler solution that just uses equality checking on the cases -
(defn cases [v & args]
(let [clauses (partition 2 2 args)]
(some #(when (= (first %) v) (second %)) clauses)))
=> (cases EventType/received EventType/send "A" EventType/received "B")
=> "B"

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

In clojure, how does one thrush through a list of functions?

In clojure, I would like to push a thrush value through a list of functions, but I'm not sure how to do so in an idiomatic way. The idea is that I will have a list containing an unknown number of functions, and I'd like to take advantage of the variadic nature of thrush.
So, something like this...
(->> 1 inc inc inc)
; 4
(->> 1 '(inc inc inc))
; does not work, of course
reduce does this nicely in this context
user> (reduce #(%2 %1) 1 [inc inc inc])
4
user> (defn thrush [val funs] (reduce #(%2 %1) val funs))
#'user/thrush
user> (thrush 1 [inc inc inc dec])
3
When possible sitck to functions over macros for such things
I think comp is the most idiomatic option here, though it will have prefix syntax instead. This is also more in keeping with normal Clojure (fn args) notation.
=> ((comp inc inc inc) 1)
4
Combine it with the idiomatic apply if a function normally takes variadic arguments, but you want to feed it a collection.
=> ((apply comp (repeat 3 inc)) 1)
4
Be aware though it threads from right to left
=> ((comp str inc inc inc) 1)
"4"
=> ((comp inc inc inc str ) 1)
ClassCastException java.lang.String cannot be cast to java.lang.Number
This also complies more with Clojure/Lisp s-expressions.
If you want more 'easy' human readable notation, Arthur Ulfeldt's answer is perfecly acceptable, and a nice example of reduce and functional programming. Using it 'as is' might get in the way of getting acquainted with the 'simplicity' of s-expressions though..
Be careful with macro's !
The reason why -> and ->> are macro's is that they actively rewrite forms, so you can use normally incomplete argument notation like (filter odd?) in their scope without having to resort to overuse of partial. This can't be done with normal function compostition.
Best learn to make the most of normal function composition before turning to macro's. There's a lot of pitfalls in them for the unaccustomed, and should be used sparingly.
How about:
user=> (def my-fns [inc inc inc])
#'user/my-fns
user=> (->> 1 ((apply comp my-fns)))
4
I suppose you could do this:
(defmacro thrush-list [x flist] `(->> ~x ~#flist))
(thrush-list 1 [inc inc inc])
; 4