language.vocabulary.idioms

table of contents
(ns language.vocabulary.idioms
  (:require [clojure.test :refer [deftest is are run-tests]]))

Idioms and common phrases

all of that and we still can't say anything useful...

let's build something very simple together and see how that works out:

If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9.

The sum of these multiples is 23.

Find the sum of all the multiples of 3 or 5 below 1000.

using clojure's bare building blocks:

(defn euler1-loop-recur [m]
  (loop [n 0 ;; our looping index
         sum 0] ;; our accumulator
    (let [over? (>= n m) ;; our halt condition
          div-by-3? (= 0 (mod n 3))
          div-by-5? (= 0 (mod n 5))]
      (if over? sum
          (recur (inc n) ;; our recursive tail call!
                 (if (or div-by-3? div-by-5?)
                   (+ sum n)
                   sum))))))

yes that is a cool recursive way to do it, but is not pleasant at all...

you could try to be less of a micro-manager

and some more familiar

constructs with something like:

(defn euler1-for-macro [m]
  (apply +
    ;; sum everything in the collection that comes next
         (for [n (range 1 m)
    ;; this works as a python-style generator
               :when (or (= 0 (mod n 3))
                         (= 0 (mod n 5)))]
    ;; just yield a list of these n's that pass the `when` test
           n)))

that still screams of foreign accent...

not that there's anything wrong with it,

but if you want to talk like the natives,

you could try something like:

(defn euler1-threading-sequences [m]
  ;; a pipeline!
  (->> m
       ;; an input collection, just data
       (range 1)
       ;; composable filter, it is just a function
       (filter #(or (= 0 (mod % 3))
                    (= 0 (mod % 5))))
       ;; a reduction, which internally uses a loop-recur 
       (reduce +)))

we could even go deeper into a cool feature called transducers, but that is a bit beyond what you need to get by on your first trip

but how can we be sure something works? testing of course!

(deftest euler-problem-1
  (is (= 23 (euler1-loop-recur 10)))
  (is (= 23 (euler1-for-macro 10)))
  (is (= 23 (euler1-threading-sequences 10))))

or you can generic assertions

(deftest euler-problem-1-but-cooler
  (are [solve] (= 23 (solve 10))
    euler1-loop-recur
    euler1-for-macro
    euler1-threading-sequences))

and you can run them programatically with:

(run-tests)

there is still more to learn, so on to an exercise!

(assuming you already have the whole setup work-book)