Clojure Goodness: Repeating A Value Or Function Invocation
In Clojure we can use the repeat
function to get an infinite sequence of a given value. We can pass a length argument to get a fixed size sequence of the value. Clojure also provides the repeatedly
function that takes as argument a function without arguments. A infinite sequence of invocations of the function is returned. Just like with the repeat
function we can pass a length argument so the returned sequence has a fixed size.
We use the repeat
and repeatedly
function in the following example:
(ns mrhaki.core.repeat
(:require [clojure.test :refer [is]])
(:import (java.time LocalTime)))
;; repeat creates an infinite sequence of the given value.
(is (= ["Clojure" "Clojure" "Clojure"]
(take 3 (repeat "Clojure"))))
;; We can pass a length argument to restrict the number of
;; times the value is repeated.
(is (= ["rocks" "rocks" "rocks"]
(repeat 3 "rocks")))
(defn parrot-talk
[s]
(repeat 2 s))
(is (= ["Polly wants a cracker" "Polly wants a cracker"]
(parrot-talk "Polly wants a cracker")))
(defn before?
"Helper function returns true if t1 is before t2, false otherwise"
[[^LocalTime t1 ^LocalTime t2]]
(.isBefore t1 t2))
(defn current-time
"Return current time"
[]
(LocalTime/now))
;; repeatedly create an infinite sequence of function invocations.
;; The function must have no arguments.
(is (before? (take 2 (repeatedly current-time))))
(is (before? (repeatedly 2 current-time)))
(defn latest-time
"Get the 'latest' time from a collection with time values."
[coll]
(reduce (fn [latest time] (if (.isAfter latest time) latest time)) coll))
(def current-times (repeatedly 100 current-time))
;; as each time is later than the next time value
;; the following equation must be true.
(is (= (latest-time current-times) (last current-times)))
Written with Clojure 1.10.1.