Updated clojure doc

This commit is contained in:
Adam 2013-07-01 14:50:59 -07:00
parent e5d2150714
commit 34c86dc958

View File

@ -2,7 +2,7 @@
language: clojure
author: Adam Bard
author_url: http://adambard.com/
filename: test.clj
filename: learnclojure.clj
---
Clojure is a Lisp family language developed for the Java Virtual Machine. It has
@ -24,9 +24,9 @@ and often automatically.
;
; The clojure reader assumes that the first thing is a
; function or macro to call, and the rest are arguments.
;
; Here's a function that sets the current namespace:
(ns test)
; The first call in a file should be ns, to set the namespace
(ns learnclojure)
; More basic examples:
@ -71,6 +71,7 @@ and often automatically.
; Collections & Sequences
;;;;;;;;;;;;;;;;;;;
; Lists are linked-list data structures, while Vectors are array-backed.
; Vectors and Lists are java classes too!
(class [1 2 3]); => clojure.lang.PersistentVector
(class '(1 2 3)); => clojure.lang.PersistentList
@ -79,16 +80,18 @@ and often automatically.
; it to stop the reader thinking it's a function.
; Also, (list 1 2 3) is the same as '(1 2 3)
; "Collections" are just groups of data
; Both lists and vectors are collections:
(coll? '(1 2 3)) ; => true
(coll? [1 2 3]) ; => true
; "Sequences" (seqs) are abstract descriptions of lists of data.
; Only lists are seqs.
(seq? '(1 2 3)) ; => true
(seq? [1 2 3]) ; => false
; Seqs are an interface for logical lists, which can be lazy.
; "Lazy" means that a seq can define an infinite series, like so:
; A seq need only provide an entry when it is accessed.
; So, seqs which can be lazy -- they can define infinite series:
(range 4) ; => (0 1 2 3)
(range) ; => (0 1 2 3 4 ...) (an infinite series)
(take 4 (range)) ; (0 1 2 3)
@ -97,8 +100,8 @@ and often automatically.
(cons 4 [1 2 3]) ; => (4 1 2 3)
(cons 4 '(1 2 3)) ; => (4 1 2 3)
; Use conj to add an item to the beginning of a list,
; or the end of a vector
; Conj will add an item to a collection in the most efficient way.
; For lists, they insert at the beginning. For vectors, they insert at the end.
(conj [1 2 3] 4) ; => [1 2 3 4]
(conj '(1 2 3) 4) ; => (4 1 2 3)
@ -168,20 +171,26 @@ x ; => 1
; => "Hello Finn, you passed 3 extra args"
; Hashmaps
; Maps
;;;;;;;;;;
; Hash maps and array maps share an interface. Hash maps have faster lookups
; but don't retain key order.
(class {:a 1 :b 2 :c 3}) ; => clojure.lang.PersistentArrayMap
(class (hash-map :a 1 :b 2 :c 3)) ; => clojure.lang.PersistentHashMap
; Arraymaps will automatically become hashmaps through most operations
; if they get big enough, so you don't need to worry.
; Maps can use any hashable type as a key, but usually keywords are best
; Keywords are like strings with some efficiency bonuses
(class :a) ; => clojure.lang.Keyword
; Maps can use any type as a key, but usually keywords are best
(def stringmap (hash-map "a" 1, "b" 2, "c" 3))
(def stringmap {"a" 1, "b" 2, "c" 3})
stringmap ; => {"a" 1, "b" 2, "c" 3}
(def keymap (hash-map :a 1 :b 2 :c 3))
keymap ; => {:a 1, :c 3, :b 2} (order is not guaranteed)
(def keymap {:a 1, :b 2, :c 3})
keymap ; => {:a 1, :c 3, :b 2}
; By the way, commas are always treated as whitespace and do nothing.
@ -200,7 +209,8 @@ keymap ; => {:a 1, :c 3, :b 2} (order is not guaranteed)
(stringmap "d") ; => nil
; Use assoc to add new keys to hash-maps
(assoc keymap :d 4) ; => {:a 1, :b 2, :c 3, :d 4}
(def newkeymap (assoc keymap :d 4))
newkeymap ; => {:a 1, :b 2, :c 3, :d 4}
; But remember, clojure types are immutable!
keymap ; => {:a 1, :b 2, :c 3}
@ -271,6 +281,7 @@ keymap ; => {:a 1, :b 2, :c 3}
(require 'clojure.string)
; Use / to call functions from a module
; Here, the module is clojure.string and the function is blank?
(clojure.string/blank? "") ; => true
; You can give a module a shorter name on import
@ -314,4 +325,56 @@ keymap ; => {:a 1, :b 2, :c 3}
(doto (Calendar/getInstance)
(.set 2000 1 1 0 0 0)
.getTime) ; => A Date. set to 2000-01-01 00:00:00
; STM
;;;;;;;;;;;;;;;;;
; Software Transactional Memory is the mechanism clojure uses to handle
; persistent state. There are a few constructs in clojure that use this.
; An atom is the simplest. Pass it an initial value
(def my-atom (atom {}))
; Update an atom with swap!.
; swap! takes a function and calls it with the current value of the atom
; as the first argument, and any trailing arguments as the second
(swap! my-atom assoc :a 1) ; Sets my-atom to the result of (assoc {} :a 1)
(swap! my-atom assoc :b 2) ; Sets my-atom to the result of (assoc {:a 1} :b 2)
; Use '@' to dereference the atom and get the value
my-atom ;=> Atom<#...> (Returns the Atom object)
@my-atom ; => {:a 1 :b 2}
; Here's a simple counter using an atom
(def counter (atom 0))
(defn inc-counter []
(swap! counter inc))
(inc-counter)
(inc-counter)
(inc-counter)
(inc-counter)
(inc-counter)
@counter ; => 5
; Other STM constructs are refs and agents.
; Refs: http://clojure.org/refs
; Agents: http://clojure.org/agents
```
### Further Reading
This is far from exhaustive, but hopefully it's enought o get you on your feet.
Clojure.org has lots of articles:
[http://clojure.org/](http://clojure.org/)
Clojuredocs.org has documentation with examples for most core functions:
[http://clojuredocs.org/quickref/Clojure%20Core](http://clojuredocs.org/quickref/Clojure%20Core)
4Clojure is a great way to build your clojure/FP skills:
[http://www.4clojure.com/](http://www.4clojure.com/)
Clojure-doc.org (yeah, really) has a number of getting started articles:
[http://clojure-doc.org/](http://clojure-doc.org/)