Search

Dark theme | Light theme

April 16, 2020

Clojure Goodness: Reapply Function With Iterate To Create Infinite Sequence

The iterate function create a lazy, infinite 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 lazy infinite 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.