Clojure

Table of Contents

1 Emacs

It is called cider

First, `lein new hello-world` to create a hello-world project.

Navigate emacs to one of the files or the directory inside the project and call `cider-jack-in`.

1.1 Eval

  • cider-eval-last-sexp (C-x C-e)
  • cider-eval-defun-at-point (C-M-x)
  • cider-interrupt: interrupt pending evaluation
  • cider-macroexpand-1 (C-c C-m)
  • cider-load-buffer
  • cider-refresh: reload all modified files
  • cider-inspect (C-c M-i)

1.2 Navigation

  • cider-switch-to-repl-buffer (C-c C-z)
  • cider-quit

1.3 Doc

  • cider-doc (C-c C-d C-d)
  • cider-javadoc (C-c C-d C-j): display in browser

1.4 Tests

  • cider-test-run-test: run test at point
  • cider-test-rerun-test: rerun the last test
  • cider-test-run-project-tests
  • cider-test-rerun-failed-tests
  • cider-test-show-report

2 Lein

lein new hello-world
cd hello-world
lein deps # install deps
lein repl # start repl

3 A first try

3.1 Setup

First, install clojure and lein2.

To start a new project:

lein new myproj
cd myproj
lein repl

This will install dependencies and enter repl.

3.2 Type

Since clojure sits on top of JVM, the type seems to be the same, and you can get the type of something by the function type.

user=> (type 3)
;; java.lang.Long
user=> (type :cat)
clojure.lang.Keyword

A list of types

java.lang.Long
(type 3)
clojure.lang.BigInt
(type 5N)
java.lang.Integer
(type (int 0))
java.lang.Short
(type (short 0))
java.lang.Byte
(type (byte 0))
java.lang.Double
(type 1.23)
java.lang.Float
(type (float 1.23))
java.lang.String
(type "cat")
clojure.lang.Symbol
(class 'str)
clojure.lang.Keyword
(type :cat)
clojure.lang.PersistentList
(type '(1 2 3))
clojure.lang.PersistentVector
(type [1 2 3])
clojure.lang.PersistentHashSet
#{:a :b :c}
clojure.lang.PersistentArrayMap
{:name "mittens" :weight 9 :color "black"}

3.3 Function

let
fn
lambda function
def
symbol
defn
define a named function

3.4 Macro

defmacro

3.5 State

3.5.1 delay

Basically this is an abstraction of function: define a function will not evaluate function body. So delay works similar: the call to delay returns an Delay Object, which can be called on by deref to evaluate the body.

(def later (fn [] (prn "Adding") (+ 1 2)))
(later) ;; => print output

(def later (delay (prn "Adding") (+ 1 2)))
(deref later) ;; => print output

The difference between a delay and a function:

  • function evaluate every time it is called
  • delays only evaluate their expressions once. They remember their value, after the first evaluation, and return it for every successive deref.

The delay opeartor: @later is equivalent to (deref later).

3.5.2 Future

This is for parallel.

I don’t need the result of evaluating these expressions yet, but I’d like it later. Could you start working on it in the meantime?

(def x (future (prn "hi") (+ 1 2)))
(deref x) ;; => 3

The body of future is executed in a new thread in parallel! Deref it will get the value of the last expression. Like delays, the expressions are only evaluated once.

3.5.2.1 Atom

The parallel program brings thread-safe problem: modify something at the same time in different threads. Clojure has a atom function to protect a data and ensure its thread-safety.

Use reset! to set value of atom, and use swap! to update.

(def xs #{})
(dotimes [i 10] (future (def xs (conj xs i))))
user=> xs ;; => #{1 4 5 7}

(def xs (atom #{}))
(dotimes [i 10] (future (swap! xs conj i)))
user=> @xs ;; => #{0 1 2 3 4 5 6 7 8 9}
3.5.2.2 Ref

Atom is linearizable, but not serializable: it does not guarantee orders. Ref is serializable.

Use ref-set to set value of a ref, and use alter to update. They must be in a dosync block, and the block order is guaranteed.

user=> (def x (ref 0))
user=> (def y (ref 0))
user=> (dosync
         (ref-set x 1)
         (ref-set y 2))
2
user=> [@x @y]
[1 2]

user=> (def x (ref 1))
user=> (def y (ref 2))
user=> (dosync
         (alter x + 2)
         (alter y inc))
3
user=> [@x @y]
[3 3]

If some of the refs do not need order, you can boost the program by release that, using commute:

user=> (dosync
         (commute x + 2)
         (commute y inc))

Finally, you can use ensure to update one ref using another, guaranteeing order.

user=> (dosync
         (alter x + (ensure y)))

3.5.3 Promise

Delays defer evaluation, and futures parallelize it. What if we wanted to defer something we dont even have yet? To hand someone an empty box and, later, before they open it, sneak in and replacing its contents with an actual gift?

(def box (promise))
(deref box) ;; empty
(deliver box :live-scorpiojns!)
(deref box) ;; => live-scorpiojns!
(deliver box :puppy) ;; => nil
(deref box) ;; => live-scorpiojns!

Some highlights:

  • box contains nothing initially
  • can be delivered
  • cannot be re-delivered

4 clojure.core

  • *in*
  • *out*
  • *err*
  • assert

4.1 Namespace

Namespaces are maps that map name to var. Namespace is seperated by dot, similar to java. The recommended format: org.lib.funcgroup.

  • clojure.core/ns: [name docstring? attr-map? references*]
    • set *ns* to name
    • references are same as calling them, except arguments are not quoted
      • (:refer-clojure …)
      • (:require …)
      • (:use …)
      • (:import …)
      • (:load …)
      • (:gen-class)
  • require [& args]: The scope will be available, the functions under them can be called using the scope.
    • load libs, skip already loaded.
    • do not usually use directly, use in ns instead
    • args can be a single symbol, or with options. It recognizes options
      • :as sym: as a symbol. e.g. (require [clojure.walk :as walk])
      • :refer sym-list: the list of symbols inside the lib can be called without the scope. The list can be :all
  • refer [ns-sym &filters]: refer to all public vars of ns into current namespace. Filters:
    • :exclude list-of-symbols
    • :only list-of-symbols
    • :rename map-of-fromsymbol-tosymbol
  • refer-clojure [& filters]: same as (refer 'clojure-core <filters>). clojure-core is refered by default, so this is typically used with exclude filter.
  • use [& args]: do not use after clojure 1.4. Use require with :refer instead
    1. require
    2. refer the lib's namespace
  • import [& import-symbols-or-lists]: as import a java classes and make them usable in their short name in clojure
    • since we have the rest sign &, the arguments are not inside a list, but as multiple arguments for import
    • as the argument name indicates, it can be symbol or list
      • symbol: is the full java class, e.g. java.util.Date
      • list: to save some typing, if importing multiple classes from same namespace: [java.util.concurrent Executors TimeUnit]

5 Type

5.1 Number

5.1.1 Arithmetic

  • +-*/
  • quot
  • rem
  • mod
  • inc
  • dec
  • max
  • min
  • with-precision

5.1.2 Compare

  • =
  • ==
  • not=
  • <, <=, >, >=

5.1.3 Bitwise

  • bit-and
  • bit-or
  • bit-xor
  • bit-flip
  • bit-not
  • bit-clear
  • bit-set
  • bit-shift-right
  • bit-shift-left
  • bit-test

5.1.4 Cast

  • byte
  • short
  • int
  • long
  • float
  • double
  • bigint
  • bigdec
  • num
  • rationalize

5.1.5 Predicate

  • nil?
  • identical?
  • zero?
  • pos?
  • neg?
  • even?
  • odd?

Other

  • number?
  • rational?
  • integer?
  • ratio?
  • decimal?
  • float?

5.1.6 Random

  • rand
  • rand-int

5.2 symbols & keywords

literals for keywords: :kw, :my.ns/kw, ::in-cur-ns

5.3 String

5.3.1 Use

  • count
  • get
  • subs
  • join
  • escape
  • split
  • split-lines
  • replace
  • replace-first
  • reverse
  • index-of
  • last-index-of

5.3.2 Regex

  • #"pattern"
  • re-find
  • re-seq
  • re-matches
  • re-pattern
  • re-matcher
  • re-groups
  • replace
  • replace-first
  • re-quote-replacement

5.3.3 Letter

  • capitalize
  • lower-case
  • upper-case

5.3.4 trim

  • trim
  • trim-newline
  • triml
  • trimr

5.3.5 Predicate

  • string?
  • blank?
  • starts-with?
  • ends-with?
  • includes?

5.3.6 characters

  • literals: \a \newline
  • char
  • char?
  • char-name-string
  • char-escape-string

6 Collections

6.1 Collection

6.1.1 Generic

  • count
  • empty
  • not-empty

6.1.2 ops

  • into
  • conj
  • walk
  • prewalk
  • prewalk-demo
  • prewalk-replace

6.1.3 Predicates

  • distince?
  • empty?
  • every?
  • not-every?
  • some
  • not-any?

6.1.4 Capabilities

  • sequential?
  • associative?
  • sorted?
  • counted?
  • reversible?
  • coll?
  • list?
  • vector?
  • set?
  • map?
  • seq?
  • record?
  • map-entry?

6.2 List

  • list
  • list*
  • first
  • nth
  • peek
  • .indexOf
  • .lastIndexOf
  • cons
  • conj
  • rest
  • pop

6.3 Vector

6.3.1 Create

  • [ ]
  • vector
  • vec
  • vector-of
  • mapv
  • filterv
  • vector-of

6.3.2 Examine

  • nth
  • get
  • peek

7 Reference

Some interesting projects: