From 34c86dc9583b43935e6fe292fbd3aaa69c4ef048 Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 1 Jul 2013 14:50:59 -0700 Subject: Updated clojure doc --- clojure.html.markdown | 91 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 77 insertions(+), 14 deletions(-) diff --git a/clojure.html.markdown b/clojure.html.markdown index cb202a92..39a27bcf 100644 --- a/clojure.html.markdown +++ b/clojure.html.markdown @@ -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/) -- cgit v1.2.3