annotate 6-Clojure/README.txt @ 79:29025305bbb7

Add notes and exercises from Day 1 of Clojure
author IBBoard <dev@ibboard.co.uk>
date Sat, 01 Jun 2019 20:10:59 +0100
parents
children a83309cdf5d3
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
79
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
1 Install Clojure with "curl -O https://download.clojure.org/install/linux-install-1.10.0.442.sh; chmod +x linux-install-1.10.0.442.sh; sudo ./linux-install-1.10.0.442.sh" (it's a downloader that downloads the real package)
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
2
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
3 Clojure has a repl (clj), which needs rlwrap ("sudo zypper in rlwrap"). This then downloads some MORE files from Maven. Don't you just LOVE the Java ecosystem?!
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
4
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
5 Clojure is a Lisp dialect. It feels a little like Prolog in that it's logic and brackets galore, but Prolog is about predicates and pattern matching whereas Lisp has more of an imperative language with odd syntax
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
6 but sensible things like "if" statements. It uses strong, dynamic typing.
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
7
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
8 Running commands at the repl and prints output *and* the return value (which can be "nil").
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
9
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
10 Commands are prefix, not infix:
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
11 "Normal" languages: 1 + 1
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
12 Clojure: (+ 1 1)
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
13
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
14 Division of integers creates a (normalised) "ratio" type to maintain accuracy:
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
15 (/ 2 4) → 1/2
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
16 (/ 2.0 4) → 0.5
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
17
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
18 Prefix does have its advantages, though - it's more like a function and can have variable numbers of parameters:
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
19 (+ 2 2 2 2) → 8
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
20
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
21 And it can be used to check order:
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
22 (< 1 2 3) → true
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
23 (< 1 3 2 4) → false
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
24
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
25 Strings are double-quoted, but characters can be escaped with a backslash outside quotes to become a string. When done with "str" it makes a string:
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
26 (str \h \e \l \l \o) → "hello"
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
27 This seems like it would rarely be useful.
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
28
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
29 Strings and characters are different (just like in Java)
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
30 (= "a" \a) → false
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
31
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
32 Clojure can pass code as arguments, e.g.:
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
33 (if true (println "It's true!"))
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
34 but that's quite normal for functional languages.
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
35
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
36 The "if" function is basically "if <condition> <true>[ <false>]".
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
37
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
38 Note: 0 and "" are true but nil is false, so only false and the null value are falsey.
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
39
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
40 Clojure has four main data structures - lists (for code), vectors (for data), sets and maps.
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
41
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
42 You can't build a list Python style with "(1 2 3)". You need either "(list 1 2 3)" or the odd syntax "'(1 2 3)".
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
43 Lists can then be operated on with "first", "last", "rest" and "cons" (construct from head and tail) functions.
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
44 There are also functions like "nth" (nth <list> <0-based index>)
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
45
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
46 Vectors use sequare brackets. They're like a list, but you can implicitly index them (i.e. you don't need "nth") by doing ([vector] pos) because they're treated as functions.
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
47
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
48 first, last and rest can be used for pattern matching.
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
49
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
50 Sets use hash followed by squiggly brackets (which is easily confused with a map). Sorted sets use "(sorted-set <values> …)".
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
51 Manipulating sets is less clean - (clojure.set/union <set1> <set2>) for unioning sets and (clojure.set/difference <set1> <set2>) for difference.
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
52 Sets are also functions and so you can check if an item is in a set with (#{set} <value>). Returns "nil" if not in the set, else returns the value.
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
53
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
54 Maps are defined with squiggly brackets and have implicit key-value positions, so you can write"{:chewie :wookie :lea :human}" for keys :chewie and :lea with values :wookie and :human.
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
55 You can also put in commas, though.
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
56
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
57
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
58 ":text" appears to be a unique identifier ("keyword"), but the book doesn't mention this until three pages after it started using it. They're like Ruby symbols and Prolog/Erland atoms.
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
59 Symbols point to something else and keywords point to themselves (although it isn't made clear what that means).
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
60 Keywords are also functions, so (map key) and (key map) are equivalent.
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
61
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
62 Maps can be merged with "merge" or with "merge-with", which takes a function to calculate the merged value.
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
63
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
64 Variables are assigned to with "(def <variable-name> <value>)". Functions are defined with "(defn <func-name> [<params list>] (<body>))".
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
65 There's also an optional docstring after <func-name>. Docs can be read with "(doc <func-name>)".
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
66
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
67 Function arguments can be quite complex and use pattern matching, e.g. getting the second value in a vector with:
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
68 (defn line-end [[_ second]] second)
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
69 which takes a single arg (the vector "[_ second]") and the body just returns "second". Clojure calls this "destructuring". It ignores any additional values (e.g. "[_ c]" matches "[1 2 3 4 5]" and puts "2" in c and ignores the trailing 3,4,5).
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
70
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
71 Where "def" is used for long-term variables (which are created in user-space - the return result is #'user/<def-name>), "let" is used for local variables, which is useful within function definitions, e.g.:
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
72 (defn centre_space [board] (let [[_ [_ c]] board] c))
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
73 which is a function with one argument (board) where the function body uses "let" with a vector containing a pattern to match and a variable to match against, and then a function that uses that vector.
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
74
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
75 There are also anonymous functions that use "(fn [args] (body))" - like a defn, but without a name. Alternatively, "#(function-body-with-%-as-a-variable)" defines an anonymous "reader macro" function with % bound to each value.
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
76 (map (fn [w] (* 2 (count w))) my_list)
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
77 is equivalent to:
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
78 (map #(* 2 (count %)) my_list)
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
79
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
80 As well as the map function, there's "apply" and "filter".
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
81
29025305bbb7 Add notes and exercises from Day 1 of Clojure
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
82 Also, some helper functions exist, like "odd?".