This is a study note of the part I: Basics of the book Getting Clojure.

1 Hello Clojure

Some basic examples:

  • Use ; for end of line comment; Use ;; for a comment in its line.
  • (str 3 "2" "hi") converts its parameters to strings and concatenates them together.
  • (count "string") counts the length of a string.
  • nil, true and false are predfined constants.
  • (println "anything" true false nil): prints parameters separted by a space.
  • basic math operators/functions take a variable number of arguments.
  • (/ 8 3) gives 8/3, it has a built-in type of ratio.
  • (quot 8 3) to get the quotient.
  • a commas , is a white space in Clojure.

Use def to bind an identifier to a value. The identifier is called a symbol in Clojure. Clojure programmers use all-lower-case-kabab-case to name a symbol. The naming rules for symbols are:

  • cannot start with a digit or a colon :. The colon is used for keywords.
  • cannot inlucde special characters such as parentheses, square brackets, braces, @ and ^.
  • most characters such as &, |, or - can be used in a symbol name.

2 Vectors and Lists

  • a vector is an ordered collections of items that can be of different types.
  • a vector literal is created by putting values inside a pair of brackets or using the vector function.
  • functions working with vectors: count, nth, first
  • a vector can be called like a function with an index parameter.
  • the rest returns a sequence represented as items in parentheses or [] if a vector only has zero or one item.
  • (conj v item) appends an item and returns a vector.
  • (cons item v) prepends an item and returns a sequence.

  • () is an empty list

  • Use a single quote ' to create non-empty list: '(1, "two", 3.0). The ' is used to tell Clojure that this is a list data, not executable code.

  • Use list function to create a list.

  • The functions count, nth, first, rest work with a list.

  • (conj l item) create a new list by prepending an item to a list

  • (cons item l) also prepends an item.

  • A vector is like an array and a list is implemented as a linked list.

  • It is easy to prepend items to a list and append items to a vector.

  • Clojure uses persistent data to mean the data is immutable and efficient.

  • Programmers mostly use vector except writing code literals.

3 Map and Set

  • Map can be called as a funciton, get nil if the key doesn’t exist or the key’s value is nil.
  • Use contains? to check if a key exists.
  • Keyword is a special type whose names follow the same rules as symbols
    • Keywords are interned strings that are part of the program
    • primarily used as keys in maps
    • used as a marker/label/flag
    • used as states
  • call the keyword like a funciton
  • assoc adds elements and dissoc removes elements
  • keys and vals return keys and values of a map
  • count, first, rest treats maps as a collection of two-element vectors.
  • Use sorted-map to have a sorted map.
  • both map types don’t support nth.
  • use , to separate map key-value pairs

  • Sets are about membership.

  • Both set and keyword can be called as a function: return the value or a nil.

  • Set can have nil as its element

  • Uses contains to return a true/false of membership

4 Logic

  • false and nil are falsy, everything else is truthy.
  • and and or return one truthy or falsy value of their parameters.
  • Testing functions: =, not=, >, >=, <, <=.
  • do evaluates multiple express and return the last value.
  • when evaluate multiple expressions when the condition is truthy, else return nil
  • cond takess multiple pairs of expressions, use :else for the catch-all.
  • when match a single value.
    • constants in case expression are not evaluated
    • the last catch-all is optional but generate an error if no match
  • try evalutes all experssion till the first catch
  • throw raise an clojure.lang.ExceptionInfo exception using ex-info funciton.

5 More Capable Functions

  • multi-arity function implements filling in defaults for different arities.
  • use [& args] for varargs or variadic functions.
  • you can mix multi-arity with variadic.
  • multimethod allows you to pick an implementation based on a splitting function. The splitting function can be a custom function, keyword or built-in functions such as class.
  • use loop, recur for recurssive functions.
  • add docstring after symbol names in function defintion.
  • use :pre and :post to check pre and post-conditions

6 Functional Things

  • Functional toolkit: apply, partial, complement, every-pred.
  • Function on the fly: fn.
  • Function literal: #(...), %, %1, %2, %3.
  • In the wild: update, update-in, assoc-in.

7 Let

  • let is local binding, def is global and stable binding.
  • let can have multiple bindings and multiple expressions.
  • if-let and when-let

8 Def, Symbols, and Vars

  • def binds a symbol to a value
  • The def binding is stable and global. it is part of the environment.
  • Symbols are values. Evaluating a symbol gets the bound value. Use 'name to get a symbol even it is not used in a def.
  • A var is a binding of def that is accessed by #'symbol-name. It have methods such as .get, .sym.
  • Use (def ^:dynamic *dynamic-symbol* value) to define a dynamic var.
  • Use binding [*symbol* value] to change it in a scope.
  • Use set! to change a dynamic var from inside a binding.
  • In the wild: *print-length*, *1, *2, *3, *e.

9 Namespaces

  • When boot up, the current namespace is user.
  • (ns name) create and set current namespace.
  • A fully-qualified symbol has a namespace.
  • Use require 'namesapce or :require namespace to load a namespaace
  • Use :as to define alias. :refer pulls vars. :refer :all pulls all vars.
  • By convention, a namespace maps a file path. . is a folder and - is _.
  • *ns* returns current namespace.
  • ns-map 'name list all vars; find-ns 'name get a namespace.
  • namespace get the namespace of a symbol.
  • Keywords have a namespace.
  • Namespace doesn’t have a hierarchy.
  • Namespace loads once. uses :reload to reload. Use defonce to enforce load once.