Search

May 20, 2020

Clojure Goodness: Composing Functions With comp

In Clojure we can use the comp function to create a new function based on multiple other functions. We create a new function by composing other functions. We can invoke the function that is returned from the comp function with input arguments. These arguments are applied to the right most function that was used with comp. Then the output of that function is the input for the next function.

In the following example code we see several usages of the comp function. Also we see how the ordening of the functions can change the output:

(ns mrhaki.core.comp
  (:require [clojure.test :refer [is]]
            [clojure.string :as str]))

;; Some functions that work with numbers.
(defn f [x] (+ 11 (- x 90)))
(defn g [x] (* 2 x))

;; Use comp to create a new function based
;; on functions f and g.
;; Function are applied from right to left,
;; so first f and then g.
(is (= 42 ((comp g f) 100)))

;; Notice ordering is important.
;; In this case first g, then f is applied.
(is (= 121 ((comp f g) 100)))


;; User data to work with.
(def user {:name "Hubert" :alias "mrhaki"})

;; Simple function to repeat the value twice.
(def duplicate (partial repeat 2))

;; Compose new function from functions
;; :alias (keyword function), 
;; str/capitalize and
;; duplicate.
;; Function are applied from right to left.
(is (= '("Mrhaki" "Mrhaki")
       ((comp duplicate str/capitalize :alias) user)))

;; Other alternatives to chaining functions
(is (= '("Mrhaki" "Mrhaki")
       ;; using an anonymous function
       (#(duplicate (str/capitalize (:alias %1))) user)
       ;; or thread macro
       (-> user :alias str/capitalize duplicate)
       ;; or simply nested functions.
       (duplicate (str/capitalize (:alias user))))) 

Written with Clojure 1.10.1.

May 13, 2020

Clojure Goodness: Using The range Function

In Clojure we can use the range function to create a lazy sequence of numbers. We can optionally specify a start value, end value and define the steps between the numbers. If we use the end value argument that value is exclusive for the returned values in the lazy sequence.

In the following example we invoke the range function with different arguments:

(ns mrhaki.core.range
  (:require [clojure.test :refer [is]]))

;; range function without arguments returns
;; an infinitive lazy sequence of numbers.
(is (= '(0 1 2 3 4) (take 5 (range))))

;; We can specifyt the start value for 
;; a lazy sequence of infinitive numbers.
(is (= '(0 1 2 3 4) (range 5)))

;; With the second argument we set the
;; end value for our lazy sequence of numbers.
;; The end value is exclusive for the range.
(is (= '(5 6 7 8 9) (range 5 10)))

;; The third argument defines the step value
;; between numbers, which by default is 1.
(is (= '(0 2 4 6 8) (range 0 10 2)))

;; We can also have a lazy sequence counting 
;; numbers back.
(is (= '(5 4 3 2 1) (range 5 0 -1)))

(is (= '(100 97 94 91 88) (take 5 (range 100 0 -3))))

Written with Clojure 1.10.1.

May 12, 2020

Clojure Goodness: Set Default Value For nil Function Argument With fnil

The function fnil can be used to create a new function from an existing function where we define default values for arguments that can be nil. Especially when we want to use a function that we didn't write ourselves this can be helpful to handle nil values in a consistent way. We can prevent for example a NullPointerException by setting a default value. We can define default values for a maximum of three arguments for the original function. When we invoke the function that is returned from the fnil function any extra arguments after the first arguments are simply passed on to the original function.

In the following example code we define a new times function based on the * function. In the example we define a default value for the first three arguments.

(ns mrhaki.core.fnil
  (:require [clojure.test :refer [is]]))

;; + throws NullPointerException when argument is nil.
(is (thrown? NullPointerException (+ nil 1)))

;; Create new function with default 0 when argument is nil.
(is (= 1 ((fnil + 0) nil 1)))


(def times 
  "Return function * with 
  default value 1 for argument 1 when nil,
  default value 10 for argumen 2 when nil and
  default value 100 for argument 3 when nil."
  (fnil * 1 10 100))

(is (= 2 
       (times nil 2)
       (* 1 2)))

(is (= 20 
       (times 2 nil) 
       (* 2 10)))

(is (= 2000 
       (times 2 nil nil) 
       (* 2 10 100)))

(is (= 200
       (times nil 2 nil)
       (* 1 2 100)))

(is (= 20
       (times nil nil 2)
       (* 1 10 2)))

;; We can use more arguments that are passed
;; to the original * function.
(is (= 4000 
       (times 2 nil nil 2)
       (* 2 10 100 2)))

(is (= 1000
       (times nil nil nil)
       (* 1 10 100)))

(is (= 2000
       (times nil nil nil 2)
       (* 1 10 100 2)))

Written with Clojure 1.10.1.

April 28, 2020

Clojure Goodness: Partition Collection Into Sequences

Clojure has the partition, partition-all and partition-by functions to transform a collection into a list of sequences with a (fixed) number of items. We can set the number of items in each sequence by providing a number as the first argument of the partition and partition-all functions. Any remainder elements are not in the resulting list of sequences when we use partition, but are when we use partition-all. We can also specify another collection to use values from to fill up the remainder as the third argument of the partition function.
Optionally we can specify an offset step value as a second argument using both functions. This mean a new partition sequence will start based on stepping through the original collection with the given step value.
Finally we can use a function to define when a new partition must start with the partition-by function. Every time the function returns a new value a new partition will begin.

In the following example Clojure code we use all three functions with all possible arguments:

(ns mrhaki.core.partition
  (:require [clojure.test :refer [is]]))

;; Sample string (a sequence of characters).
(def letters "aBCdeFg")

;; First argument defines how many items are in each partition.
;; Any remainder is ignored. 
(is (= [[\a \B] [\C \d] [\e \F]] (partition 2 letters)))

;; With partition-all the remainder is part of the result.
(is (= [[\a \B] [\C \d] [\e \F] [\g]] (partition-all 2 letters)))


;; The second argument is a step offset.
(is (= [[\a \B] [\d \e]] (partition 2 3 letters)))

(is (= [[\a \B] [\d \e] [\g]] (partition-all 2 3 letters)))

(is (= [[\a \B \C] [\C \d \e] [\e \F \g]] (partition 3 2 letters)))

(is (= [[\a \B \C] [\C \d \e] [\e \F \g] [\g]] (partition-all 3 2 letters)))


;; The third argument is used to fill the last remainder partition if needed.
(is (= [[\a \B \C] [\d \e \F] [\g \! \?]] (partition 3 3 [\! \? \@] letters)))

(is (= [[\a \B \C] [\d \e \F] [\g \! \!]] (partition 3 3 (repeat \!) letters)))

;; When padding collection has not enough items, only what is available
;; is used to fill the remainder part.
(is (= [[\a \B \C] [\d \e \F] [\g \!]] (partition 3 3 [\!] letters)))


;; Using partition-by we can use a function that perfoms the split
;; when the function returns a new value.
(is (= [[\a] [\B \C] [\d \e] [\F] [\g]]
       (partition-by #(Character/isUpperCase %) letters)))

(is (= [[ 1 2 3 4] [5] [6 7 8 9] [10] [11 12 13 14]]
       (partition-by #(= 0 (mod % 5)) (range 1 15))))

Written with Clojure 1.10.1.

April 24, 2020

Clojure Goodness: Counting Frequency Of Items In A Collection

If we want to know how often an item is part of a collection we can use the frequencies function. This function returns a map where each entry has the item as key and the number of times it appears in the list as value.

In the following example Clojure code we use the frequencies function:

(ns mrhaki.core.frequencies
  (:require [clojure.test :refer [are is]]))


(def sample "Clojure is cool!")

(is (= {\space 2 \! 1 \C 1 \c 1 \e 1 \i 1 \j 1 \l 2 \o 3 \r 1 \s 1 \u 1}
       (frequencies sample))
    "Frequency of each character in sample")


(def list ["Clojure" "Groovy" "Cool" "Goodness"])

(is (= {\C 2 \G 2}
       (frequencies (map first list)))
    "Two words start with C and two with G")


(def numbers '(29 31 42 12 8 73 46))

(defn even-or-odd
  "Return string even when number is even, 
   otherwise return string odd."
  [n]
  (if (even? n)
    "even"
    "odd"))

(is (= {"odd" 3 "even" 4}
       (frequencies (map even-or-odd numbers)))
    "list numbers has 3 odd and 4 even numbers")


(def user {:user "mrhaki" :city "Tilburg" :age 46})

(is (= {java.lang.String 2 java.lang.Long 1}
       (frequencies (map type (vals user))))
    "user map has two values of type String and 1 of type Long")

Written with Clojure 1.10.1.

April 23, 2020

Awesome Asciidoctor: Image As Link Reference

To make an image linkable in Asciidoctor when formatted to HTML we must use the link attribute when we use the image macro. The value of the link attribute is the address where the user goes when clicking on the image. We can also specify extra link attributes like window to specify the target window for the link to open in.

In the following example we use the link attribute for a block and inline image, with and without an extra window attribute:

= Image with link

== Simple link

Using the `link` attribute with `image:`

image::haki-logo.png[link="https://www.mrhaki.com"]
A block image.

image:haki-logo.png[link="https://www.mrhaki.com"]
As inline image.

== Link attributes

Set link attribute `window="_blank"` to open link in new browser window:

image::haki-logo.png[link="https://www.mrhaki.com",window="_blank"]

When we transform this markup to HTML we get the following HTML for the images:

...
<div class="paragraph">
<p>Using the <code>link</code> attribute with <code>image:</code></p>
</div>
<div class="imageblock">
<div class="content">
<a class="image" href="https://www.mrhaki.com"><img src="./images/haki-logo.png" alt="haki logo"></a>
</div>
</div>
<div class="paragraph">
<p>A block image.</p>
</div>
<div class="paragraph">
<p><span class="image"><a class="image" href="https://www.mrhaki.com"><img src="./images/haki-logo.png" alt="haki logo"></a></span>
As inline image.</p>
</div>
</div>
...
<div class="imageblock logo">
<div class="content">
<a class="image" href="https://www.mrhaki.com" target="_blank" rel="noopener"><img src="./images/haki-logo.png" alt="haki logo"></a>
</div>
...

Written with Asciidoctor 2.0.9.

April 22, 2020

Clojure Goodness: Check Substring Is Part Of String

Sometimes we want to see if a string is part of another string. Or if the string value starts or ends with a certain string. In Clojure we can use the includes? function from the clojure.string namespace to check if a string is part of another string value. To see if a string starts with a certain value we can use the starts-with? function from the clojure.string namespace. And to check if a string ends with a given value we use ends-with? from the same namespace.

In the next example code we use these functions and also add a matches? function to check if a string matches with a regular expression defined in a string:

(ns mrhaki.string.includes
  (:require [clojure.string :as str]
            [clojure.test :refer [is]]))

;; String to check.
(def s "Clojure is cool!")

;; Check if given value is part of the string.
(is (true? (str/includes? s "cool")))
(is (false? (str/includes? s "boring")))

;; Check string starts with given value.
(is (true? (str/starts-with? s "Clojure")))
(is (false? (str/starts-with? s "Groovy")))

;; Check string ends with given value.
(is (true? (str/ends-with? s "cool!")))

;; Helper function to see if string with regular expression
;; matches a given string value using java.lang.String#matches.
(defn matches? 
  "Return true when string `re` with regular expression
  matches for value `s`, false otherwise."
  [^CharSequence s ^CharSequence re] 
  (. s matches re))

(is (true? (matches? s ".*is.*")))
(is (false? (matches? s "cool")))

Written with Clojure 1.10.1.

April 17, 2020

Clojure Goodness: Getting Results From Multiple Functions With Juxt Function

The function juxt can be used to get results from multiple functions on the same argument in one go. We pass the functions we want to invoke as arguments to the juxt function. This results in a new function that will return a vector with the results from each original function that is passed to the juxt function. So the first element in the result vector is the result of the first function, the second element is the result of the second function and so on. The documentation of the juxt function shows this clearly as ((juxt a b c)) => [a(x) b(x) c(x)].

In the following example we use the juxt function to apply multiple functions on a string, collection and map:

(ns mrhaki.core.juxt
  (:require [clojure.test :refer [is]]))

;; The functions first, last and count are applied
;; to the string value and we get a vector
;; with the result of each function.
(is (= [\C \e 18]
       ((juxt first last count) "Clojure is awesome")))


(defn sum 
  "Calculate sum of values in collection"
  [coll] 
  (apply + coll))

(defn avg 
  "Calculate average of values in collection"
  [coll] 
  (/ (sum coll) (count coll)))

;; Create new function summarize to give back statistics
;; on a collection based on count, min, max, sum and average.
(def summarize (juxt count #(apply min %) #(apply max %) sum avg))

(is (= [4 1 108 171 171/4]
       (summarize [1 20 42 108])))

(let [[count min max sum avg] (summarize [1 20 42 108])]
  (is (= 4 count))
  (is (= 1 min))
  (is (= 108 max))
  (is (= 171 sum))
  (is (= 171/4 avg)))


;; As keywords are functions we can use them to get values
;; for keys in a map.
(is (= ["Hubert" "mrhaki"]
       ((juxt :name :alias) {:alias "mrhaki" :name "Hubert" :location "Tilburg"})))

Written with Clojure 1.10.1.

April 16, 2020

Clojure Goodness: Reapply Function With Iterate To Create Infinitive Sequence

The iterate function create a lazy, infinitive sequence based on function calls. The iterate function takes a function and an initial value as arguments. The first element in the sequence is the initial value, next the function is invoked with the previous element as argument and this continues for each new element. Suppose we have a function #(+ 2 %) that adds 2 to the input argument. Then if we use this function with iterate and start with value 1 the first elements of the sequence will be 1, (+ 2 1), (+ 2 3), (+ 2 5). So first element is the initial value, next element is the invocation of the function with input argument 1. The result of this function is 3, which is then the input for the function to calculate the next element and so on.

In the following example code we use iterate in different scenario's:

(ns mrhaki.core.iterate
  (:require [clojure.test :refer [is]]))

;; Lazy sequence of numbers in steps of 2.
(def odds (iterate #(+ 2 %) 1))

(is (= (list 1 3 5 7 9 11 13 15 17 19)
       (take 10 odds)))


;; Define lazy sequence with a growing string.
;; The first element is ar, next argh, then arghgh etc.
(def pirate (iterate #(str % "gh") "ar"))

(def crumpy-pirate (nth pirate 5))

(is (= "arghghghghgh" crumpy-pirate))


;; Function that returns the given amount
;; plus interest of 1.25%.
(defn cumulative-interest
  [amount]
  (+ amount (* 0.0125 amount)))

;; Lazy sequence where each entry is the 
;; cumulative amount with interest based 
;; on the previous entry. 
;; We start our savings at 500.
(def savings (iterate cumulative-interest 500))

;; After 5 years we have:
(is (= 532.0410768127441
       (nth savings 5)))


;; Function to double a given integer
;; and return as bigint.
(defn doubler [n] (bigint (+ n n)))

;; Define layz infinitive sequence
;; where each element is the doubled value
;; of the previous element.
(def wheat-chessboard (iterate doubler 1))

;; First elements are still small.
(is (= (list 1 2 4 8 16 32)
       (take 6 wheat-chessboard)))

;; Later the elements grow much bigger.
(is (= (list 4611686018427387904N 9223372036854775808N)
       (->> wheat-chessboard (drop 62) (take 2))))

;; Sum of all values for all chessboard squares
;; is an impressive number.
(is (= 18446744073709551615N 
       (reduce + (take 64 wheat-chessboard))))

Written with Clojure 1.10.1.

April 13, 2020

Clojure Goodness: Combine First And Next Functions Multiple Times

The first function in Clojure returns the first item of a collection. The next function returns a new sequence with all elements after the first element from a collection. Clojure adds some utility methods to combine first and next with different combinations. We can use the function ffirst which is will return the first element of the first element of a collection and the nfirst function to get the next elements from the first element of a collection. We can use the function fnext to get the first element of the next elements of a collection and the function nnext to get the next elements of the next elements of a collection.

In the following example we use the ffirst, nfirst, fnext and nnext:

(ns mrhaki.seq
  (:require [clojure.test :refer [is]]))

(def langs [{:language "Clojure" :site "https://clojure.org" :dynamic true}
            {:language "Groovy" :site "https://www.groovy-lang.org" :dynamic true}
            {:language "Java" :site "https://www.java.com" :dynamic false}
            {:language "Kotlin" :site "https://kotlinlang.org" :dynamic false}])

;; Find first map entry of first map in languages.
(is (= [:language "Clojure"]
       (ffirst langs)
       (first (first langs))))

;; Find next map entries for first map in languages.
(is (= (list [:site "https://clojure.org"] [:dynamic true])
       (nfirst langs)
       (next (first langs))))

;; Find first map of next maps in languages.
(is (= {:language "Groovy" :site "https://www.groovy-lang.org" :dynamic true}
       (fnext langs)
       (first (next langs))))

;; Find next maps of next maps in languages.
(is (= (list {:language "Java" :site "https://www.java.com" :dynamic false}
             {:language "Kotlin" :site "https://kotlinlang.org" :dynamic false})
       (nnext langs)
       (next (next langs))))

Written with Clojure 1.10.1.