Ian Jones Logo

Clojure For the Brave and True

tags

Clojure

keywords

Clojure (Computer program language)

Clojure for the brave and true: learn the ultimate language and become a better programmer

4 Core Func tions in Dep th

Programming to Abstractions

Treating Lists, Vectors, Sets, and Maps as Sequences

5 Functional Progr amming

The core concepts you’ll learn include:

  • what pure functions are and why they’re useful

  • how to work with immutable data structures and why they’re superior to their mutable cousins

  • how disentangling data and functions gives you more power and flexibility

  • why it’s powerful to program to a small set of data abstractions

Pure Functions: What and Why

It always returns the same result if given the same arguments. This is called referential transparency, and you can add it to your list of $5 programming terms.

It can’t cause any side effects. That is, the function can’t make any changes that are observable outside the function itself—for example,

This makes your functions easier to reason about because they can't change anything outside of their scope.

Pure functions rely on their own arguments and constant values to determine their return value

Not Referentially Transparent

(defn analyze-file
[filename]
(analysis (slurp filename)))

; but this one is:

(defn analysis
  [text]
  (str "Character Count: " (count text)))

To perform a side effect is to change the association between a name and its value within a given scope.

Side effects are potentially harmful, however, because they introduce uncertainty about what the names in your code are referring to.

Functions with side effects, on the other hand, place more of a bur- den on your mind grapes: now you have to worry about how the world is affected when you call the function.

Living with Immutable Data Structures

Recursion Instead of for/while

(def great-baby-name "Rosanthony")
great-baby-name

(let [great-baby-name "Bloodthunder"]
great-baby-name)

great-baby-name
#'user/great-baby-name
"Rosanthony"
"Bloodthunder"
"Rosanthony"

Clojure lets you work around this apparent limitation with recursion.

(defn my-sum
  ([vals] (my-sum vals 0))
  ([vals accumulating-total]
   (if (empty? vals)
     accumulating-total
     (my-sum (rest vals) (+ (first vals) accumulating-total)))))

(my-sum [39 5 1])
#'user/my-sum
45

Chapter 6

We use namespaces for organizing our code.

you can refer to the current namespace with ns

(ns-name *ns*)
user

You can have more than one namespace.

Quoting any Clojure form tells Clojure not to evaluate it but to treat it as data

inc
'inc
(map inc [1 2])
'(map inc [1 2])
#function[clojure.core/inc]
inc
(2 3)
(map inc [1 2])

Storing Objects with def

Declaring a def is called interning a var.

(def great-books ["East of Eden" "The Glass Bead Game"])
(ns-interns *ns*)
#'user/great-books
{great-books #'user/great-books}
#'user/great-books is the reader form of a var.

You can deref vars to get the objects they point to:

(deref #'user/great-books)
@#'user/great-books
great-books
["East of Eden" "The Glass Bead Game"]
["East of Eden" "The Glass Bead Game"]
["East of Eden" "The Glass Bead Game"]

Creating and Switching to Namespaces

Three tools for creating namespaces:

  • create-ns

  • in-ns

  • ns (macro)

Using in-ns is more common because it creates the namespace if it doesn’t exist and switches to it

You can access vars in other namespaces with their fully qualified symbols.

using fully qualified symbols can become burdensome.

refer lets you refer to other namespace's symbols.