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
3.6 TODO Logistics
3.7 TODO Modeling
3.8 TODO Debugging
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)
- set
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. Userequire
with:refer
instead- require
- 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]
- symbol: is the full java class, e.g.
- since we have the rest sign
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
- https://clojure.github.io/ is the API reference, in alphabet order
Some interesting projects:
- SuperCollider is a server and a language for music synthesizing.
- Overtone offers a clojure wrapper and emacs environment for the SuperCollider backend.
- https://github.com/ring-clojure/ring
- http://liquidz.github.io/
- https://github.com/liquidz/misaki
- http://nakkaya.com/