├── .gitignore
├── Gruntfile.js
├── LICENSE
├── README.md
├── index.html
├── package.json
├── resources
├── BalancedBinaryTree.png
├── ClojureEvaluation.png
├── TraditionalEvaluation.png
├── UnbalancedBinaryTree-01.png
├── UnbalancedBinaryTree-02.png
├── UnbalancedBinaryTree-03.png
├── UnbalancedBinaryTree-04.png
├── UnbalancedBinaryTree.png
├── ast.png
├── lein.gif
├── lein.jpg
├── lein.png
├── light-table-unbalanced-tree-example.PNG
├── repl.png
└── vector-lookup-options.png
└── src
├── lighttable.tryout.clj
├── mbo-unbalanced-binary-tree.clj
├── repl.clj
├── scratch
├── .gitignore
├── README.md
├── doc
│ └── intro.md
├── project.clj
├── src
│ └── scratch
│ │ └── core.clj
└── test
│ └── scratch
│ └── core_test.clj
└── xors.clj
/.gitignore:
--------------------------------------------------------------------------------
1 | pom.xml
2 | *jar
3 | /lib/
4 | /classes/
5 | /targets/
6 | .lein-deps-sum
7 | /node_modules/
8 |
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | module.exports = function(grunt) {
2 |
3 | // Project configuration.
4 | grunt.initConfig({
5 | pkg: grunt.file.readJSON('package.json'),
6 |
7 | assemble: {
8 | options: {
9 | plugin: ['assemble-contrib-markdown', 'other/plugins/*']
10 | }
11 | }
12 | });
13 |
14 | grunt.loadNpmTasks('assemble' );
15 | grunt.loadNpmTasks('grunt-newer' );
16 | grunt.registerTask('default', ['newer:assemble']);
17 |
18 | };
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2013 Marko Bonaci
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | *Written in January 2014, with Clojure 1.5.1 and Leiningen 2.3.4 on Java 1.7.0_45.*
2 | _Inspired by Aphyr's excellent, Clojure from-the-ground-up tutorial and made possible by "The joy of Clojure" book. I also heavily used great "Clojure for Java programmers" talks by Rich Hickey, father of Clojure._
3 |
4 | _Inspired? Made possible? Who am I kidding, I flat out stole from those kind people._
5 |
6 |
7 | ## Clojure? That's a Lisp, for God's sake!
8 |
9 | I've been avoiding Clojure for a _long time_. Because it's a _Lisp dialect_ and I have a negative Lisp experience from school. It was either a bad timing or a bad teacher, I guess.
10 | Hmm, I guess my guessing about it, in itself, implies the answer :)
11 |
12 | > Times and times again it gets apparent to me. Late puberty and adolescence are not the right times to go wide with programming languages!
13 |
14 | # :)
15 | ### It must had something to do with the way the book was written
16 |
17 | My renewed interest in Clojure was due to a chance encounter. I stumbled upon Aphyr's (Kyle Kingsbury) fascinating [Jepsen series](http://aphyr.com/tags/jepsen), a blog about perils of uncertainty in distributed systems.
18 |
19 | There, Clojure looked terse and concise, yet expressive and simple. So I decided to give it a shot. I picked up [The joy of Clojure](http://joyofclojure.com), got in my sweatshirt, put on a headband, closed my wife and our two-month-old twins in the living room, slightly licked my finger and opened up the first page...
20 |
21 | > After the initial discovery phase, as I was going through the book, I suddenly found myself infatuated with the language. It's beautifully uniform, consistent and simple (which is different from "easy", mind you). At that point, it has just spread out to me, ready to be gulped away. And that's a great feeling!
22 |
23 | ### How would you describe Clojure?
24 |
25 | Clojure prides itself in being a **dynamic functional programming language**.
26 | It is built on three great facilities, **immutable data, first-class functions and dynamic typing**.
27 |
28 | **Immutable data** means that a function always produces the same output, given the same input and that functions are side-effects free (when a function is run, nothing changes outside that function). All collections are immutable by design. Immutability in Clojure is not optional, like for instance, in Scala.
29 |
30 | **First class functions** means that a variable can be bound to a function, that a function can be passed to another (higher-order) function or that it may be returned from a function. In short, function is data.
31 |
32 | **Dynamic typing** means that we don't declare types. Data types are resolved at runtime.
33 |
34 | > So from now on, when we say "modify", "add", "remove", ... it really means - create a "copy", modify the copy and return a reference to that new object.
35 | > But the word "copy" from the previous sentence doesn't stand for a full, brute-force copy. In order to provide immutability and still preserve the performance guarantees (big O notation), Clojure uses something called **Structural sharing**, which basically means that the data structure of the new object is built by creating references to the elements of the old object, varying only with respect to the modified elements (called **path copying**).
36 |
37 | > To picture this, think of a tree that gets a new node. Nodes of the new tree simply point to nodes of the old tree, so that, consequently, only a single full-blown node object gets created.
38 |
39 | # Setup
40 | ### Open PRs
41 |
42 |
44 |
45 | > Disclaimer: I write this as I'm going through the book myself, so bear with me. Open pull requests as you see fit
46 |
47 | OK, that's more than enough BS (for now). Let's start by setting up our Clojure runtime environment.
48 |
49 | To set it up, I suggest you use an excellent automation tool (dependency mgr, builder, test runner, packager, all-in-one) [Leiningen](http://leiningen.org/).
50 |
51 | > Notice there's no "installer" in the list of features. That's because Clojure is just another _dependency_ of "our project".
52 |
53 | For your convenience, here's a dead simple, step-by-step environment setup for Ubuntu ([other OS, sir?](http://leiningen.org/#install)):
54 |
55 |
56 |
57 |
58 | ```sh
59 | cd /usr/bin
60 | sudo curl -O https://raw.githubusercontent.com/technomancy/leiningen/stable/bin/lein
61 | sudo chmod a+x lein
62 | ```
63 |
64 | Let me explain what we just did.
65 | First we fetched `lein` script with `curl`° into `/usr/bin`°°.
66 | We made sure it's executable with `chmod`.
67 |
68 | ° Use `sudo apt-get install curl`, if you haven't installed it yet (doesn't come OOTB with Ubuntu).
69 | °° You can use any other dir, as long as you make sure it's in your PATH (check with `echo $PATH`), which makes possible to run it from anywhere.
70 |
71 | Let's kick things off:
72 |
73 | ```sh
74 | cd
75 | lein new scratch
76 | ```
77 |
78 | Here we used `lein new` to create a fresh Clojure project, based on the `scratch` template (_scratch_ - as in _scratch the surface_, I guess).
79 | Lein, in turn, installed _rest of itself_ into `~/.lein/self-installs`.
80 |
81 | In case you get stuck, visit [lein install instructions](http://leiningen.org/#install).
82 | If you want to know more, the official Leiningen tutorial can be found [right here](https://github.com/technomancy/leiningen/blob/master/doc/TUTORIAL.md).
83 |
84 | Lovely! Now fire along:
85 |
86 | ```sh
87 | cd scratch
88 | lein repl
89 | ```
90 |
91 | Boom! We have our own working Clojure environment.
92 |
93 | 
94 |
95 | REPL is short for _Read Eval Print Loop_, which is like an interactive window into a Clojure program (similar to a JavaScript console in the browser or REPL in Node).
96 |
97 | Now when that's all sorted and you're eager to learn, let's see how Clojure code looks like...
98 |
99 | # Basics
100 |
101 | A valid Clojure expression consists of _numbers_, _symbols_, _lists_, _keywords_, _booleans_, _characters_, _functions_, _function calls_, _macros_ (wtf?), _strings_, _literal maps_, _vectors_, and _sets_.
102 |
103 | All of those, except _symbols_ and _lists_, evaluate to themselves.
104 |
105 | Symbols are similar to variables in other languages, which basically means that, when a symbol is encountered, compiler tries to find the value that the symbol was previously (hopefully) bound to, which is then used in place of the symbol.
106 |
107 | Lists take a special place in Clojure (after all, Lisp means **LIS**t **P**rocessing). They are the main building block of the language.
108 | Lists start with a so called _operation form_:
109 |
110 | ```clj
111 | (op ...)
112 | ```
113 |
114 | `op` can be either:
115 | - one of very few _special operations_ (listed bellow)
116 | - a _macro_
117 | - an expression that yields a _function_
118 |
119 | For instance, if the Clojure compiler encounters:
120 |
121 | ```clj
122 | (my-fun some-expr)
123 | ```
124 |
125 | it'll first try to resolve `my-fun`, which in our case, is a previously defined function that conceptually looks like this:
126 |
127 | ```clj
128 | (def my-fun value-expr)
129 | ```
130 |
131 | Then, it'll evaluate `some-expr` and invoke the `my-fun` function, passing in the result.
132 |
133 | > so `my-fun` is a _symbol_ that is bound to a function definition
134 |
135 | Full list of **special operations**:
136 |
137 | ```clojure
138 | def ;evaluates an expression and binds the result to a symbol
139 | if ;conditional evaluation
140 | fn ;defines a function
141 | let ;establishes a name in a local lexical scope
142 | loop ;used for functional looping
143 | recur ;used to support recursion in functional looping
144 | do ;defines a block of statements
145 | new ;allocates a new java object
146 | . ;used to access a java method
147 | throw ;same as in java
148 | try ;same as in java
149 | set! ;re-binds a symbol
150 | quote ;supresses evaluation of an expression (same as single quote, ')
151 | var ;provides a mechanism to refer to a mutable storage location inside a thread (?)
152 | ```
153 |
154 | The list above may contain some descriptions that may not be clear to you, but soon, if you stuck with it, it'll all get cleared. And that's a promise.
155 |
156 | Here's how a function invocation looks like:
157 |
158 | ```clj
159 | user=> (inc 2) ;"increment 2"
160 | 3 ;this is REPL output
161 | ;=> 3 ;which I'll write like this from now on
162 |
163 | ; those three that begin with a semicolon are comments
164 | ;;this one also, from that first semicolon to the end of the line. All the way here ->
165 | ```
166 |
167 | ## Syntax
168 |
169 | ### Prefix/Polish notation
170 |
171 | ```clj
172 | ;; intentionally skipping java semicolons
173 |
174 | ;;------------------------------------
175 | ;; Java Clojure
176 | ;;------------------------------------
177 | int i = 5 (def i 5)
178 | ;;------------------------------------
179 | if(x == 0) (if (zero? x)
180 | return y y
181 | else z)
182 | return z
183 | ;;------------------------------------
184 | x * y * z (* x y z)
185 | ;;------------------------------------
186 | foo(x, y, z) (foo x y z)
187 | ;;------------------------------------
188 | ```
189 |
190 | You can try the following example in your REPL:
191 |
192 | ```clj
193 | ;skipping the 'user=>' prompt from now on
194 | (+ 1 (- 5 2) (+ 3 4))
195 | ;=> 11
196 | ```
197 |
198 | > Uh, that looks somewhat weird, right?
199 |
200 | This type of notation, inherited from Lisp, called a _prefix notation_ or _Polish notation_, may look weird at the first glance.
201 |
202 | Let's back up a bit.
203 | All programming languages, in order to execute the source code, need to parse it first.
204 | In most languages, the product of this code parsing is a so called _abstract syntax tree_ (_AST_), which is then fed into the compiler.
205 |
206 | Let's see how that tree looks for the example at hand.
207 | In Java, the expression above would be written like this:
208 |
209 | ```java
210 | 1 + (5 - 2) + (3 + 4); // parentheses left for clarity
211 | // 1 + 3 + 7
212 | // 11
213 | ```
214 |
215 | ... and the _AST_ would look like this:
216 |
217 | 
218 |
219 | After seeing what _AST_ (as the ideal structure for representing code) looks like, I argue that _prefix_ is the natural way of representing expressions.
220 |
221 | When you think of it (really hard), as early as first grade maths, the only option we ever see is _infix_ notation, so that's what gets hardwired inside our brains.
222 |
223 | That is why, IMO, the _Polish notation_ looks weird to us.
224 |
225 | > prefix notation allows any number of arguments in an operation (infix only two). Moreover, it completely eliminates the problem of operator precedence
226 |
227 | > at this point I have to stress that this is my opinion after only a couple of weeks learning Clojure. I'm slightly affraid of what would happen to me after I explore all corners of the language :)
228 |
229 | ### Clojure is different
230 |
231 | This is how a program is executed in a traditional, java-style _edit-compile-run_ way:
232 |
233 | 
234 |
235 | In Java (and it's similar in other traditional languages), the source code gets handed to the compiler, which compiles it to bytecode. The bytecode is then run on the JVM. If you need to change something in your code, e.g. fix a bug, you need to do the whole process all over again. Open up the source file, make some changes, compile the source code, then stop the whole program and finally send the new version of bytecode to the JVM to be executed.
236 |
237 | Uh, we got over that hurdle. Now we confidently start our program but we soon notice that it's still not right. OK, we stop the whole program once more and then start it in a debug mode, carefully setting breakpoints along the way. But sometimes it's not that easy, or even possible to replicate the exact context where our bug has previously occurred.
238 |
239 | > at work, we often used to spend a better half of our day in this iterative process, doing nothing. When you combine that with IBM's tooling, that becomes a nightmare. E.g. Rational IDE weighs more than a GB. Websphere application server takes ages to start. When a new developer needs to set up his environment, it has known to take a couple of days to wire all the stuff together. We are crazy! How on earth we got eased into this unproductive way of working.
240 |
241 | 
242 |
243 | Clojure's evaluation is much more dynamic, the code first goes to **Reader**, which takes the characters and turns them into Clojure data structures.
244 | The Compiler never sees the source code, it compiles the data structures produced by the Reader to bytecode, which is then run on the JVM.
245 |
246 | So what does this mean? Can such a seemingly subtle difference have a noticeable impact on our development process?
247 |
248 | The point is that, this way, we can hot-swap a part of the running code without stopping the program.
249 | The source code doesn't have to come from a file. We can use REPL to connect to a running program and evaluate expressions on the fly.
250 |
251 | The other benefit is that other programs can easily produce data structures, thus avoiding source code and Reader all together. That's the Clojure's secret sauce. It's what makes **macros** possible.
252 | When _Evaluator_, while processing source code, encounters a _macro_ (i.e. a symbol that is bound to a _macro_), it stops executing that part of the program and sends it to that _macro_, a _little side-program_ that manipulates data structures, transforming them in some useful way and then returning that, extended data structures back to the Evaluator.
253 |
254 | This is extremely powerful concept, which allows us to extend the language without waiting for Rich Hickey to do so. Overwhelming amount of things, that are built-into other languages, are just macros in Clojure. For instance:
255 |
256 | ```clj
257 | (or x y) ;'or' is a macro in Clojure
258 |
259 | ;;after being extended by or macro, becomes:
260 |
261 | (let [or__158 x]
262 | (if or__158 or__158 y))
263 | ```
264 |
265 | Don't worry if _macros_ are not clear yet (I explained them rather poorly, I know), we'll dedicate the whole chapter to that powerful construct.
266 |
267 | # Basics (this time for real)
268 |
269 | ## Scalar data types
270 |
271 | A scalar data type is the one that can only hold one value at a time (value of a number, symbol, keyword, string or a character).
272 |
273 | ### Numeric types
274 |
275 | The following examples of numeric expressions are trivial, so I suggest you try them out, in your REPL.
276 |
277 | ```clj
278 | (type 3)
279 | ;=> java.lang.Long
280 |
281 | Long/MAX_VALUE
282 | ;=> 9223372036854775807
283 |
284 | (inc (bigint Long/MAX_VALUE))
285 | ;=> 9223372036854775808N
286 |
287 | (type 5N)
288 | ;=> clojure.lang.BigInt
289 |
290 | (type (int 0))
291 | ;=> java.lang.Integer
292 |
293 | (type (short 0))
294 | ;=> java.lang.Short
295 |
296 | (type (byte 0))
297 | ;=> java.lang.Byte
298 |
299 | ;; decimal, hexadecimal, octal, radix-32, and binary literals:
300 | [127 0x7F 0177 32r3V 2r01111111]
301 | ;=> [127 127 127 127 127]
302 | ;; radix supports up to base 36
303 |
304 | (Short/MAX_VALUE)
305 | ;=> 32767
306 |
307 | (Integer/MAX_VALUE)
308 | ;=> 2147483647
309 |
310 | Byte/MAX_VALUE
311 | ;=> 127
312 |
313 | (type 1.23)
314 | ;=> java.lang.Double
315 |
316 | (type (float 1.23))
317 | ;=> java.lang.Float
318 |
319 | 366e3
320 | ;=> 366000.0
321 | ```
322 |
323 |
324 | ```clj
325 | (+ 1 2.0)
326 | ;=> 3.0
327 |
328 | (class (+ 1 2.0))
329 | ;=> java.lang.Double
330 |
331 | (= 3 3.0)
332 | ;=> false
333 |
334 | (== 3 3.0)
335 | ;=> true
336 |
337 | (* 2 3 1/5)
338 | ;=> 6/5
339 |
340 | (- 5 1 1 1)
341 | ;=> 2
342 |
343 | (- 2)
344 | ;=> -2
345 |
346 | (* 4)
347 | ;=> 4
348 |
349 | (/ 4)
350 | ;=> 1/4
351 |
352 | (+)
353 | ;=> 0 ;neutral for addition
354 |
355 | (*)
356 | ;=> 1 ;neutral for multiplication
357 |
358 | (<= 1 2 3)
359 | ;=> true
360 |
361 | (<= 1 3 2)
362 | ;=> false
363 |
364 | (= 2 2 3)
365 | ;=> false
366 |
367 | (= 2 2 2)
368 | ;=> true
369 | ```
370 |
371 | To avoid having to round floating-point numbers (e.g. result of `2 / 3`), Clojure provides a **rational** number type `clojure.lang.Ratio`, thus maintaining absolute precision when dealing with floating point arithmetic:
372 |
373 | ```clj
374 | (type 1/3)
375 | ;=> clojure.lang.Ratio
376 |
377 | ;; rational numbers are automatically simplified, if possible:
378 | 100/25
379 | ;=> 4
380 |
381 | (rational? 2) ;is rational or may be rational
382 | ;=> true
383 |
384 | (rational? 2.1)
385 | ;=> false
386 |
387 | (rationalize 2.1)
388 | ;=> 21/10
389 |
390 | (numerator (/ 21 10))
391 | ;=> 21
392 |
393 | (denominator (/ 21 10))
394 | ;=> 10
395 | ```
396 |
397 | > The calculation of rational math, though accurate, isn’t nearly as fast as with floats or doubles (due to overhead cost of e.g. finding the least common denominator).
398 |
399 | **Truncation**
400 |
401 | Truncation is a process of limiting the accuracy of floating-point numbers, due to deficiencies in its representation. When a number is truncated, its precision is limited such that the maximum number of digits of accuracy is bound by the number of bits that can fit into the storage space allowed by its representation.
402 |
403 | ```clj
404 | (let [pi-constant 3.14159265358979323846264338327950288419716939937M] ;notice the M
405 | (println (class pi-constant))
406 | pi-constant)
407 | ;=> java.math.BigDecimal
408 | ;=> 3.14159265358979323846264338327950288419716939937M
409 |
410 | (let [pi-trunc 3.14159265358979323846264338327950288419716939937]
411 | (println (class pi-trunc))
412 | pi-trunc)
413 | ;=> java.lang.Double
414 | ;=> 3.141592653589793
415 | ```
416 |
417 | `M`, at the end of a floating-point number literal is used to tell Clojure to keep the number in its full precision.
418 | `N` is used for the same thing when dealing with longs.
419 |
420 | > Clojure truncates floating point numbers by default
421 |
422 | **Promotion**
423 |
424 | Clojure is able to detect when overflow occurs. Then, it automatically promotes the value to a numerical representation that can accommodate larger values
425 |
426 | ```clj
427 | (def small 9)
428 | (class small)
429 | ;=> java.lang.Long
430 |
431 | (class (+ small 90000000000000000000))
432 | ;=> clojure.lang.BigInt
433 |
434 | (class (+ small 9.0))
435 | ;=> java.lang.Double
436 |
437 | (+ Integer/MAX_VALUE Integer/MAX_VALUE)
438 | ;=> 4294967294
439 |
440 | (class (+ Integer/MAX_VALUE Integer/MAX_VALUE))
441 | ;=> java.lang.Long
442 | ```
443 |
444 | > There's no limit to integer size in Clojure, besides RAM size
445 |
446 | ### Strings and Characters
447 |
448 | String is any sequence of characters enclosed in double quotes, including newlines:
449 |
450 | ```clj
451 | "this is a string
452 | on two lines"
453 | ;=> "this is a string\non two lines" ;REPL output includes newline escape
454 |
455 | (type "a")
456 | ;=> java.lang.String
457 |
458 | (str nil) ;'nil' is Clojure's 'null'
459 | ;=> ""
460 | ```
461 |
462 | > single quote, backtick and `quote` (though with slightly different properties) are used to include literals in a program without evaluating them
463 |
464 | ```clj
465 | (str 'cat)
466 | ;=> "cat"
467 |
468 | (str 'a')
469 | ;=> "a'"
470 |
471 | (str 1)
472 | ;=> "1"
473 |
474 | (str '1)
475 | ;=> "1"
476 |
477 | (str true)
478 | ;=> "true"
479 |
480 | (str '(1 2 3))
481 | ;=> "(1 2 3)"
482 |
483 | (str "meow " 3 " times")
484 | ;=> "meow 3 times"
485 |
486 | ;characters are denoted by backslash
487 | \a
488 | ;=> \a
489 |
490 | \u0042
491 | ;=> \B
492 |
493 | \\
494 | ;=> \\
495 | ```
496 |
497 | ## Symbols
498 |
499 | Symbols can have either short or full names. The short name is used to refer to things locally, and the _fully qualified name_ is used to refer unambiguously to a symbol (from anywhere).
500 | Symbol names are separated with a `/`. For instance, the symbol `str` is also present in a namespace called `clojure.core` and the corresponding full name is `clojure.core/str`
501 | The main purpose of symbols is to refer to _things_, i.e. to point to other values. When evaluating a program, symbols are looked up and replaced by their corresponding values.
502 |
503 | > [more about symbols](#symbols)
504 |
505 | ```clj
506 | (= str clojure.core/str)
507 | ;=> true
508 |
509 | (name 'clojure.core/str)
510 | ;=> "str"
511 | ```
512 |
513 |
514 | ## Keywords
515 |
516 | Closely related to symbols and strings are keywords, which begin with a `:`.
517 | Keywords are like strings in that they are made up of text, but are specifically intended for use as labels or identifiers. These are not labels in the sense of symbols, keywords are not replaced by any other value, they are just names, by themselves:
518 |
519 | ```clj
520 | (type :cat)
521 | ;=> clojure.lang.Keyword
522 |
523 | (str :cat)
524 | ;=> ":cat"
525 |
526 | (name :cat)
527 | ;=> "cat"
528 | ```
529 |
530 | **Using keywords as map keys**
531 |
532 | > since keywords are self-evaluating and provide fast equality checks, they are almost always used as map keys
533 |
534 | Another important property of keywords, when used as map keys, is that they can be used as functions, taking a map as an argument to perform value lookups:
535 |
536 | ```clj
537 | (def mouse-planet {:cats 180, :mice 9}) ;define a map
538 | ;=> #'user/mouse-planet
539 |
540 | (:cats mouse-planet) ;lookup by keyword
541 | ;=> 180
542 |
543 | (println (/ (:cats mouse-planet) ;much more useful example
544 | (:mice mouse-planet))
545 | "cats per capita")
546 | ;=> 20 cats per capita
547 | ```
548 |
549 | **As enumerations**
550 |
551 | Since their value doesn't change, convenient keyword use case is enumeration. E.g. `:mouse`, `:rat` and `:x-rat` provide a nice visual delineation (for mouse types) within a source code.
552 |
553 | > there are other useful things we can do with keywords. We can use them **As multimethod dispatch values** and **As directives**, but we'll deal with that later
554 |
555 | **Qualifying your keywords**
556 |
557 | Keywords don't belong to any specific namespace, although it's a good practice to define them as if they do, because that way you provide a context:
558 |
559 | ```clj
560 | user=> :not-in-ns
561 | ;=> :not-in-ns
562 |
563 | user=> ::not-in-ns ;fully qualified keyword
564 | ;=> :user/not-in-ns
565 |
566 | user=> (ns another)
567 | ;=> nil
568 |
569 | another=> :user/in-another ;"fully qualified" keyword
570 | ;=> :user/in-another
571 |
572 | another=> :haunted/name ;namespace doesn't have to exist
573 | ;=> :haunted/name
574 | ```
575 |
576 | > double colon is used to fully qualify a keyword by prepending the current namespace name to the keyword name
577 |
578 | > equally named keywords are the same object in memory
579 |
580 | ## Booleans
581 |
582 | Only `false` and `nil` are logical `false`, all others values are `true`:
583 |
584 | ```clj
585 | (boolean nil)
586 | ;=> false
587 |
588 | (boolean 0)
589 | ;=> true
590 |
591 | (boolean "hi")
592 | ;=> true
593 |
594 | (boolean str)
595 | ;=> true
596 |
597 | (and true false true)
598 | ;=> false
599 |
600 | (and true true true)
601 | ;=> true
602 | ```
603 |
604 | ... and returns the first _falsy_ value, or the last value if all are _truthy_:
605 | ```clj
606 | (and 1 2 3)
607 | ;=> 3
608 |
609 | (and -1 nil 2)
610 | ;=> nil
611 | ```
612 |
613 | or returns the first _truthy_ value, or the last value if all are _falsy_:
614 | ```clj
615 | (or false 2 3)
616 | ;=> 2
617 |
618 | (or false false nil)
619 | ;=> nil
620 | ```
621 |
622 | `not` inverses the _truthiness_ of the expression:
623 | ```clj
624 | (not nil)
625 | ;=> true
626 | ```
627 |
628 | ## Regular expressions
629 |
630 | `#"..."` is Clojure’s way of writing a regular expression.
631 | Clojure and Java have very similar Regex syntax.
632 |
633 | ```clj
634 | (re-find #"cat" "mystic cat mouse")
635 | ;=> "cat"
636 |
637 | (re-find #"cat" "only dogs here")
638 | ;=> nil
639 | ```
640 |
641 | The parentheses, i.e. _capturing group_ means that the regular expression should capture that part of the match. We get back a _list_ containing the part of the string that matched the first parentheses, followed by the part that matched the second parentheses, etc:
642 |
643 | ```clj
644 | (re-matches #"(.+):(.+)" "mouse:treat")
645 | ;=> ["mouse:treat" "mouse" "treat"]
646 |
647 | ;; capturing group in the regex causes each returned item to be a vector:
648 | (re-seq #"\w*(\w)" "one-two/three")
649 | ;=> (["one" "e"] ["two" "o"] ["three" "e"])
650 | ```
651 |
652 | Java's regex `Pattern` class has several methods that can be used directly, but only `split` is used regularly to split a string into an array of Strings:
653 |
654 | ```clj
655 | (seq (.split #"," "1,2,3,4")) ;this is how you call Java methods
656 | ;=> ("1" "2" "3" "4")
657 | ```
658 |
659 | [Java interoperability section.](#java-interop)
660 |
661 | The `re-seq` function returns a lazy sequence of all matches in a string:
662 |
663 | ```clj
664 | (re-seq #"\w+" "one-two/three")
665 | ;=> ("one" "two" "three")
666 | ```
667 |
668 | > Java's regex engine includes a `Matcher` object which mutates in a non-thread-safe way as it walks through a string finding matches. This object is exposed in Clojure through the `re-matcher` function and can be used in combination with `re-groups` and `re-find`.
669 | It's recommended to avoid direct usage of all of these three functions.
670 |
671 | # Collections
672 |
673 | A collection is a group of values. It’s a container which provides some structure, some framework, for the things that it holds. We refer to collection members as elements, or items.
674 |
675 | All Clojure's collections support heterogeneous values (values of arbitrary types), together, in the same collection.
676 |
677 | > when a collection is evaluated (except lists), each of its contained items is evaluated first
678 |
679 | Most of functions that work on collections aren't actually written to work on concrete collection types, but rather to work on abstract data types. For instance, some of abstractions in this space are:
680 |
681 | - Collection (common to all concrete types)
682 | - Sequential (ordered collections are lists and vectors)
683 | - Associative (maps associate keys with values, vectors associate indices with values)
684 | - Indexed (vectors, for example, can be quickly indexed into)
685 |
686 | ## Lists
687 |
688 | A `PersistentList` is a singly linked list where each node knows its distance from the end.
689 | List elements can only be found by starting with the first element and walking each prior node in order.
690 | List elements can only be added or removed from the left end.
691 |
692 | In idiomatic Clojure code, lists are used almost exclusively to represent code forms, e.g. to call functions, macros, ...
693 | Code forms are then `eval`-ed or used as the return value for a macro.
694 |
695 | > Lists are rarely used for anything other than to represent Clojure source code, because they rarely offer any value over vectors
696 |
697 | Literal lists are written with parentheses: `(yankee hotel foxtrot)`.
698 |
699 | When a list is evaluated, the first item of the list, `yankee`, will be resolved to a _function_, _macro_, or _special form_.
700 | If `yankee` is a _function_, the remaining items in the list will be evaluated in order, and the results will be passed to `yankee` as its parameters.
701 | If `yankee` is a _macro_ or a _special form_, the remaining items in the list
702 | aren’t necessarily evaluated, but are processed as defined by the _macro_ or _operator_.
703 |
704 | > **special form** is a form with special syntax or special evaluation rules that are typically not implemented using the base Clojure forms. An example of a special form is
705 | the `.` (dot) operator used for Java interoperability purposes.
706 |
707 | ```clj
708 | (cons 1 (2 3))
709 |
710 | ;=> ClassCastException java.lang.Long cannot be cast to clojure.lang.IFn
711 | ;;which basically means that the number 2 cannot be used as a function
712 |
713 | (cons 1 '(2 3))
714 | ;=> (1 2 3)
715 | ```
716 |
717 | Remember, we quote lists (and everything else that needs quoting) with a `'` (or `quote`) to prevent them from being evaluated.
718 |
719 | ```clj
720 | '(1 2 3)
721 | ;=> (1 2 3)
722 |
723 | (type '(1 2 3))
724 | ;=> clojure.lang.PersistentList
725 | ```
726 |
727 | There's also a **syntax-quote** (back-tick), which automatically qualifies all unqualified symbols in its argument:
728 |
729 | ```clj
730 | `map
731 | ;=> clojure.core/map
732 |
733 | `(map even? [1 2 3])
734 | ;=> (clojure.core/map clojure.core/even? [1 2 3])
735 | ```
736 |
737 | You can also construct a list using `list`:
738 |
739 | ```clj
740 | (list 1 2 3)
741 | (1 2 3)
742 | (= (list 1 2) (list 1 2))
743 | true
744 | ```
745 |
746 | You can modify a list by _conjoining_ an element onto it (as always with lists, the new element goes to the beginning):
747 |
748 | ```clj
749 | (conj (list 1 2 3) 4)
750 | ;=> (4 1 2 3)
751 |
752 | (first (list 1 2 3))
753 | ;=> 1
754 |
755 | (second (list 1 2 3))
756 | ;=> 2
757 |
758 | (nth (list 1 2 3) 2)
759 | ;=> 3
760 | ```
761 |
762 | Unlike some _Lisps_, the empty list in Clojure, `()`, isn't the same as `nil`.
763 | Lists are well-suited for small collections, or collections which are read in linear order, but are slow when you want to get arbitrary elements from later in the list.
764 |
765 | > Calling `seq` on a list returns the list itself, but more often, calling `seq` on a collection returns a new `seq` object for navigating that collection.
766 |
767 | ### What lists aren't?
768 |
769 | Probably the most common misuse of lists is to hold items that will be looked up by index. Though you can use `nth` to get the element, Clojure will have to walk the list from the beginning to find it.
770 |
771 | Lists aren't queues. You can add items to one end, but you can't remove from the other.
772 |
773 | ### PersistentQueue
774 |
775 | Persistent immutable queue is a FIFO structure where `conj` adds to the rear, `pop` removes from the front and `peek` returns the front element without removal.
776 |
777 | Clojure currently doesn't provide a core construction function for creating persistent queues, but there's a readily available empty queue instance to use, `clojure.lang.PersistentQueue/EMPTY`.
778 |
779 | The printed representation for Clojure's queues isn't particularly informative, but we can change that by providing a method for them on the `print-method`:
780 |
781 | ```clj
782 | (defmethod print-method clojure.lang.PersistentQueue
783 | [q, w]
784 | (print-method '<- w) (print-method (seq q) w) (print-method '-< w))
785 |
786 | clojure.lang.PersistentQueue/EMPTY
787 | ;=> <-nil-<
788 | ```
789 |
790 | > Popping an empty queue results in just another empty queue. Peeking an empty queue returns `nil`
791 |
792 | The mechanism for adding an element to a queue is `conj`:
793 |
794 | ```clj
795 | (def tasks
796 | (conj clojure.lang.PersistentQueue/EMPTY
797 | :wake-up :shower :brush-teeth))
798 | ;=> #'mbo/tasks
799 |
800 | tasks
801 | ;=> <-(:wake-up :shower :brush-teeth)-<
802 | ```
803 |
804 | > Clojure's persistent queue is implemented internally using two separate collections, the front being a seq and the rear being a vector. All insertions occur in the rear vector and all removals occur in the front seq, taking advantage of each collection's strength. When all the items from the front have been popped, the back vector is wrapped in a seq to become the new front and an empty vector is used as the new back
805 |
806 | To get the front element, we use `peek`:
807 |
808 | ```clj
809 | (peek tasks)
810 | ;=> :wake-up
811 | ```
812 |
813 | To remove elements from the front of a queue, we use `pop` (although possible, it's non-idiomatic and suboptimal to use `rest` with queues, because it returns a seq, not a queue and _screws up_ the speed guarantees):
814 |
815 | ```clj
816 | (pop tasks) ;; returns new list, remember?
817 | ;=> <-(:shower :brush-teeth)-<
818 |
819 | (rest tasks)
820 | ;=> (:shower :brush-teeth)
821 | ```
822 |
823 | ## Vectors
824 |
825 | For fast access to every element, we use a __vector__.
826 | Vectors are surrounded by square brackets, just like lists are surrounded by parentheses. Because vectors aren’t evaluated like lists are, there is no need to quote the vector literal:
827 |
828 | ```clj
829 | [1 2 3]
830 | ;=> [1 2 3]
831 |
832 | (type [1 2 3])
833 | ;=> clojure.lang.PersistentVector
834 | ```
835 |
836 | > Vectors are similar to arrays, but are immutable and persistent
837 |
838 | You can also create vectors with `vector`, or change other structures into vectors with `vec`:
839 |
840 | ```clj
841 | (vector 1 2 3)
842 | ;=> [1 2 3]
843 |
844 | (vec (list 1 2 3))
845 | ;=> [1 2 3]
846 | ```
847 |
848 | `conj` on a vector adds to the end, not the start, like with lists:
849 |
850 | ```clj
851 | (conj [1 2 3] 4)
852 | ;=> [1 2 3 4]
853 | ```
854 |
855 | Our friends `first`, `second`, and `nth` work here too; but unlike lists, `nth` is fast on vectors. That’s because internally, vectors are represented as a very broad tree of elements, where each part of the tree branches into 32 smaller trees. Even very large vectors are only a few layers deep, which means getting to elements only takes a few hops, which is why retrieval operation from the interior of a vector takes essentially a constant time.
856 |
857 | The important difference, when compared to lists, is that vectors evaluate each item in order. No function or macro is performed on a vector itself.
858 |
859 | `rest` and `next` both return _everything but the first element_. They differ only by what happens when there are no remaining elements:
860 |
861 | ```clj
862 | (rest [1 2 3 4])
863 | ;=> (2 3 4)
864 |
865 | (next [1 2 3 4])
866 | ;=> (2 3 4)
867 | ```
868 |
869 | `rest` returns logical `true`, `next` returns logical `false`. Each has their uses, but in almost every case they’re equivalent:
870 |
871 | ```clj
872 | (next [1])
873 | ;=> nil
874 |
875 | (rest [1])
876 | ;=> ()
877 | ```
878 |
879 | `last`, surprisingly, returns the last element:
880 |
881 | ```clj
882 | (last [1 2 3])
883 | ;=> 3
884 | ```
885 |
886 | `count`, shockingly, returns element count:
887 |
888 | ```clj
889 | (count [1 2 3 4])
890 | ;=> 4
891 | ```
892 |
893 | You can use element's index to access it:
894 |
895 | ```clj
896 | ([1 2 3] 1) ;vectors are in fact functions of their indices
897 | ;=> 2
898 | ```
899 |
900 | Vectors and lists containing the same elements are considered equal:
901 |
902 | ```clj
903 | (= [1 2] (list 1 2))
904 | ;=> true
905 | ```
906 |
907 | If you already have a vector but want to "pour" several values into it, use `into`:
908 |
909 | ```clj
910 | (let [m-vector [:a :b :c]]
911 | (into m-vector (range 10)))
912 | ;=> [:a :b :c 0 1 2 3 4 5 6 7 8 9]
913 |
914 | ;;if you want to return a vector the first arg to 'into' must be a vector
915 | ;;the second argument must be anything that works with 'seq' function
916 | ```
917 |
918 | ### Primitive vectors
919 |
920 | You can store primitive types inside of vectors using the `vector-of` function, which takes any of `:int`, `:long`, `:float`, `:double`, `:byte`, `:short`, `:boolean` and `:char` and returns an empty vector. This returned vector will act just like any other vector, except that, internally, it'll store its contents as primitives.
921 | The new vector will try to coerce any additions into its internal type when they are being added:
922 |
923 | ```clj
924 | (into (vector-of :int) [Math/PI 2 1.3])
925 | ;=> [3 2 1]
926 |
927 | (into (vector-of :char) [100 101 102])
928 | ;=> [\d \e \f]
929 |
930 | (into (vector-of :int) [1 2 609812734019519652839108477134])
931 |
932 | ;=> IllegalArgumentException Value out of range for long: 60981273401951...
933 | ;=> clojure.lang.RT.longCast (RT.java:1134)
934 | ```
935 |
936 | ### Large vectors
937 |
938 | Vectors are particularly efficient at three things (relative to lists):
939 | - adding or removing things from the right end of the collection
940 | - accessing or changing items in the interior of the collection by numeric index
941 | - walking in reverse order
942 |
943 | ```clj
944 | (def a-to-e (vec (map char (range 65 70))))
945 | ;=> #'mbo/a-to-z
946 |
947 | a-to-e
948 | ;=> [\A \B \C \D \E]
949 |
950 | (nth a-to-e 4) ;like with a map
951 | ;=> \E
952 |
953 | (get a-to-e 4) ;like with a map
954 | ;=> \E
955 |
956 | (a-to-e 4) ;invoking a vector as a function
957 | ;=> \E
958 | ```
959 |
960 | 
961 |
962 | Since vectors are indexed, they can be efficiently walked in either direction. The `seq` and `rseq` return sequences that do exactly that:
963 |
964 | ```clj
965 | (seq a-to-e)
966 | ;=> (\A \B \C \D \E)
967 |
968 | (rseq a-to-e)
969 | ;=> (\E \D \C \B \A)
970 | ```
971 |
972 | Any item in a vector can be "changed" using the `assoc` function (in a constant time). Clojure does this using _structural sharing_ between the old and the new vectors, hence avoiding having to copy all the elements.
973 |
974 | ```clj
975 | (assoc a-to-e 3 "former D")
976 | ;=> [\A \B \C "former D" \E]
977 | ```
978 |
979 | The `assoc` function works only on indices that either already exist or, as a special case, exactly one step past the end of a vector (returned vector becomes one item larger).
980 |
981 | Function `replace` uses `assoc` internally:
982 |
983 | ```clj
984 | (replace {2 :a, 4 :b} [1 2 3 2 3 4])
985 | ;=> [1 :a 3 :a 3 :b]
986 | ```
987 |
988 | The functions `assoc-in`, `update-in` and `get-in` are used to work with nested structures of vectors and/or maps. These functions take a series of indices to pick items from each more deeply nested level:
989 |
990 | ```clj
991 | (def matrix
992 | [[1 2 3]
993 | [4 5 6]
994 | [7 8 9]])
995 | ;=> #'mbo/matrix
996 |
997 | (get-in matrix [1 2]) ;second row, third column
998 | ;=> 6
999 |
1000 | (assoc-in matrix [1 2] 'x)
1001 | ;=> [[1 2 3] [4 5 x] [7 8 9]]
1002 | ```
1003 |
1004 | `update-in` works the similar way, but instead of taking a value to "overwrite" an existing value, it takes a function to _apply_ to an existing value. It'll replace the value at the given coordinates with the return value of the function:
1005 |
1006 | ```clj
1007 | (update-in matrix [1 2] * 100)
1008 | ;=> [[1 2 3] [4 5 600] [7 8 9]]
1009 |
1010 | ;; the coordinates refer to the value 6 and the function is * taking an argument 100
1011 | ;; so the slot becomes the return value of (* 6 100)
1012 | ```
1013 |
1014 | Remember? `matrix` itself never changed:
1015 |
1016 | ```clj
1017 | matrix
1018 | ;=> [[1 2 3] [4 5 6] [7 8 9]]
1019 | ```
1020 |
1021 | ### Vectors as stacks
1022 |
1023 | Clojure vectors uses `conj` as `push` and `pop` as `pop` to add and remove elements from the right side. Since vectors are immutable, `pop` returns a new vector with the rightmost element dropped, which is different from many mutable stack APIs, which generally return the dropped item. Consequently, `peek` becomes more important as the primary way to get an item from the top of the stack:
1024 |
1025 | ```clj
1026 | (peek m-stack)
1027 | ;=> 3
1028 |
1029 | (pop m-stack)
1030 | ;=> [1 2]
1031 |
1032 | (conj m-stack 4)
1033 | ;=> [1 2 3 4]
1034 |
1035 | (+ (peek m-stack) (peek (pop m-stack)))
1036 | ;=> 5
1037 | ```
1038 |
1039 | > If you're using a collection (any implementor of `clojure.lang.IPersistentStack`) as a stack, it's idiomatic to use `conj` instead of `assoc`, `peek` instead of `last` and `pop` instead of `dissoc`. That avoids unnecessary confusion about how the collection is being used
1040 |
1041 | > Lists also implement `IPersistentStack`, but the functions there operate on the left side, i.e. beginning of the list
1042 |
1043 | ### Using vectors instead of reverse
1044 |
1045 | When processing a list, it's pretty common to want to produce a new list in the same order. But if all you have is list, then you're left with backward list that needs to be reversed:
1046 |
1047 | ```clj
1048 | (defn m-map1 [f coll]
1049 | (loop [coll coll, acc nil]
1050 | (if (empty? coll)
1051 | (reverse acc)
1052 | (recur (next coll) (cons (f (first coll)) acc)))))
1053 | ;=> #'mbo/m-map1
1054 |
1055 | (m-map1 - (range 5))
1056 | ;=> (0 -1 -2 -3 -4)
1057 | ```
1058 |
1059 | After the entire list has been walked once to produce the desired values, `reverse` walks it again to get them in the right order, which is inefficient and non-idiomatic.
1060 | One way to avoid `reverse` is to use a vector as the accumulator, instead of a list:
1061 |
1062 | ```clj
1063 | (defn m-map2 [f coll]
1064 | (loop [coll coll, acc []]
1065 | (if (empty? coll)
1066 | acc
1067 | (recur (next coll) (conj acc (f (first coll)))))))
1068 | ;=> #'mbo/m-map2
1069 |
1070 | (m-map2 - (range 5))
1071 | ;=> [0 -1 -2 -3 -4]
1072 | ```
1073 |
1074 | ### Subvectors
1075 |
1076 | Provide a fast way to take a slice of an existing vector based on start and end indices.
1077 | To produce a subvector we use the `subvec` function:
1078 |
1079 | ```clj
1080 | (subvec a-to-e 2 4)
1081 | ;=> [\C \D]
1082 |
1083 | ;;first index is inclusive, but the second is exclusive
1084 | ```
1085 |
1086 | > There's a special logic for taking a `subvec` of a `subvec`, in which case the newest subvector keeps a reference to the original vector, not the intermediate subvector, which keeps both the creation and use of sub-subvectors fast and efficient.
1087 |
1088 | ### Vectors as MapEntries
1089 |
1090 | Clojure's hash map, just like hash tables and dictionaries in many other languages, has a mechanism to iterate through the entire collection. Clojure's solution for this iterator is, you guessed it - `seq`.
1091 | Each item in this seq needs to include both the key and the value, hence they are wrapped in a `MapEntry`. When printed, each entry looks like a vector:
1092 |
1093 | ```clj
1094 | (first {:width 10 :height 20 :depth 15})
1095 | ;=> [:depth 15]
1096 |
1097 | ;;not only does it look like a vector, it really is one:
1098 | (vector? (first {:width 10 :height 20 :depth 15}))
1099 | ;=> true
1100 |
1101 | ;;which means you can use all the regular vector functions on it
1102 | ;;it even supports destructuring*
1103 | ```
1104 |
1105 | [destructuring?](#destructuring)
1106 |
1107 | ```clj
1108 | ;;e.g. the following locals, 'dimension' and 'amount', will take on the value of each
1109 | ;;key/value pair in turn:
1110 | (doseq [[dimension amount] {:width 10, :height 20, :depth 15}]
1111 | (println (str (name dimension) ":") amount " inches"))
1112 | ;=> depth: 15 inches
1113 | ;=> width: 10 inches
1114 | ;=> height: 20 inches
1115 | ;=> nil
1116 |
1117 | (doc doseq)
1118 | ;=> -------------------------
1119 | ;=> clojure.core/doseq
1120 | ;=> ([seq-exprs & body])
1121 | ;=> Macro
1122 | ;=> Repeatedly executes body (presumably for side-effects) with
1123 | ;=> bindings and filtering as provided by "for". Does not retain
1124 | ;=> the head of the sequence. Returns nil.
1125 | ```
1126 |
1127 | A `MapEntry` is its own type and has two functions for retrieving its contents, `key` and `val`, which do exactly the same thing as `(nth m-map 0)` and `(nth m-map 1)`.
1128 |
1129 | ### What vectors aren't?
1130 |
1131 | Vectors are versatile, but there are some useful patterns where they might seem like a good fit, but in fact the aren't.
1132 |
1133 | **Vectors aren't sparse**
1134 |
1135 | If you have a vector of length _n_, the only position where you can insert a value is at index _n_, appending to the far right end. You can't skip some indices and insert at a higher index number (use hash map or sorted map).
1136 | Although you can replace values within a vector, you can't insert or delete items such that indices are adjusted (use finger trees for that).
1137 |
1138 | **Vectors aren't queues**
1139 |
1140 | Use a [PersistentQueue](#persistentqueue) for that.
1141 |
1142 | **Vectors aren't sets**
1143 |
1144 | If you want to find out whether a vector contains a particular value, you might be tempted to use the `contains?` function, but that function checks whether a specific _key_, not _value_ is in a collection, which is really not useful for a vector.
1145 |
1146 | > Vectors are probably the most frequently used collection type in Clojure. They are used as literals for argument lists and `let` bindings, for holding large amounts of application data and as stacks and map entries
1147 |
1148 | > In almost all contexts, you can consider vectors, lists, and other sequences as interchangeable. They only differ in their performance characteristics, and in a few data-structure-specific operations.
1149 |
1150 | ## Sets
1151 |
1152 | Set is a collection of unordered, unique elements.
1153 |
1154 | Sets are surrounded by `#{...}`:
1155 |
1156 | ```clj
1157 | #{1 2 3}
1158 | ;=> #{1 2 3}
1159 |
1160 | (#{:a :b :c :d} :c)
1161 | ;=> :c
1162 |
1163 | (#{:a :b :c :d} :e)
1164 | ;=> nil
1165 | ```
1166 |
1167 | If you look at the previous two expressions, you'll see that the sets are in fact functions of their elements that return the matched element or `nil` if the element is not present (take a pause and read that a couple more times, examining the examples).
1168 |
1169 | Elements can be accessed via the `get` function, which returns the queried value if it exists, or `nil` if it doesn't:
1170 |
1171 | ```clj
1172 | (get #{:a 1 2 :b} :b)
1173 | ;=> :b
1174 |
1175 | (get #{:a 1 2 :b} :k)
1176 | ;=> nil
1177 | ```
1178 |
1179 | **Searching a sequence for any of multiple items using a set and `some`**
1180 |
1181 | The `some` function takes a predicate and a sequence. It applies the predicate to each element in turn, returning the first _truthy_ value returned by the predicate or else `nil`:
1182 |
1183 | ```clj
1184 | (some #{:b} [:a 1 :b 2])
1185 | ;=> :b
1186 |
1187 | (some #{1 :b} [:a 1 :b 2])
1188 | ;=> 1
1189 | ```
1190 |
1191 | Using a set as the predicate supplied to `some` allows you to check whether any of the truthy values in the set are contained within the given sequence. This is a frequently used Clojure idiom for searching for containment within a sequence.
1192 |
1193 | The key to understanding how sets determine whether an element is discrete lies in one simple statement: Given two elements, evaluating as equal, a set will contain only one, independent of concrete types:
1194 |
1195 | ```clj
1196 | (let s #{[1 2] (1 2)}) ;vector and list with the same items are considered equal
1197 |
1198 | ;=> IllegalArgumentException Duplicate key: (1 2)
1199 | ;=> clojure.lang.PersistentHashSet.createWithCheck (PersistentHashSet.java:68)
1200 | ```
1201 |
1202 | **Sorted sets**
1203 |
1204 | To ask for elements in a sorted order:
1205 |
1206 | ```clj
1207 | (sort #{2 4 1})
1208 | ;=> (1 2 4)
1209 | ```
1210 |
1211 | As long as the arguments to the `sorted-set` function are mutually comparable, you'll receive a sorted set. Otherwise an exception is thrown:
1212 |
1213 | ```clj
1214 | (sorted-set :b :c :a)
1215 | ;=> #{:a :b :c}
1216 |
1217 | (sorted-set [3 4] [1 2])
1218 | ;=> #{[1 2] [3 4]}
1219 |
1220 | (sorted-set :b 2 :c)
1221 |
1222 | ;=> ClassCastException clojure.lang.Keyword cannot be cast to java.lang.Number
1223 | ;=> clojure.lang.Util.compare (Util.java:152)
1224 | ```
1225 |
1226 | You can use your own comparator with `sorted-set-by` function.
1227 |
1228 | **Containment**
1229 |
1230 | `contains?` checks for **existence of a key** in a collection:
1231 |
1232 | ```clj
1233 | (contains? #{1 2 3} 3)
1234 | ;=> true
1235 | ```
1236 |
1237 | Many newcomers to Clojure expect `contains?` to behave the same as Java's `java.util.Collection#contains` method, but it doesn't:
1238 |
1239 | ```clj
1240 | (contains? [1 2 4 3] 4)
1241 | ;=> false
1242 | ```
1243 |
1244 | Since `contains?` looks for existence of a key it shouldn't work with sets, but it does. That is due to the fact that sets are implemented as maps with the same element as the _key_ and _value_ with an additional check for containment before insertion.
1245 |
1246 | ### `clojure.set` namespace
1247 |
1248 | `clojure.set/intersection` function works as you might expect. Given two sets, it returns a set of the common elements. Given _n_ sets, it'll incrementally return the intersection of resulting sets and the next set:
1249 |
1250 | ```clj
1251 | (clojure.set/intersection #{:a :b :c} #{:d :c :b})
1252 | ;=> #{:b :c}
1253 |
1254 | (clojure.set/intersection #{:a :e :i :o :u}
1255 | #{:a :u :r}
1256 | #{:r :u :s})
1257 | ;=> #{:u}
1258 | ```
1259 |
1260 | `clojure.set/union` works as expected.
1261 | `clojure.set/difference` "removes" all the elements from the first set that are also present in the second set (known as _relative complement_).
1262 |
1263 | `conj` "adds" an element to the set:
1264 |
1265 | ```clj
1266 | (conj #{:a :b :c} :d)
1267 | ;=> #{:a :c :b :d}
1268 | ```
1269 |
1270 | `disj` "removes" an element:
1271 |
1272 | ```clj
1273 | (disj #{1 2} 2)
1274 | ;=> #{1}
1275 | ```
1276 |
1277 | You can make a set out of any other collection with `set`:
1278 |
1279 | ```clj
1280 | (set [2 5 1])
1281 | ;=> #{1 2 5}
1282 | ```
1283 |
1284 | ## Maps
1285 |
1286 | Map is an unsorted, associative _key/value_ structure (associates keys with values).
1287 | Maps are represented with curly braces `{...}` filled by alternating _key/value_ pairs, with or without commas:
1288 |
1289 | ```clj
1290 | {:name "luka", :weight 3 :color "white"} ;notice missing comma
1291 | ;=> {:weight 3, :name "luka", :color "white"}
1292 | ```
1293 |
1294 | We can look up the _value_ by _key_ with `get`:
1295 |
1296 | ```clj
1297 | (get {"cat" "meow", "dog" "woof"} "cat")
1298 | ;=> "meow"
1299 | ```
1300 |
1301 | `get` can also take a default value to return instead of `nil`, if the key doesn’t exist:
1302 |
1303 | ```clj
1304 | (get {:k :v} :w :default)
1305 | ;=> :default
1306 | ```
1307 |
1308 | Maps can be used as verbs, directly:
1309 |
1310 | ```clj
1311 | ({"a" 12, "b" 24} "b") ;maps are functions of their keys
1312 | ;=> 24
1313 | ```
1314 |
1315 | Keywords can also be used as verbs, which look themselves up:
1316 |
1317 | ```clj
1318 | (:raccoon {:weasel "queen", :raccoon "king"})
1319 | ;=> "king"
1320 | ```
1321 |
1322 | In addition to literal syntax, hash maps can be created with the `hash-map` function:
1323 |
1324 | ```clj
1325 | (hash-map :a 1, :b 2, :c 3, :d 4, :e 5)
1326 | ;=> {:a 1, :c 3, :b 2, :d 4, :e 5}
1327 | ```
1328 |
1329 | Maps support heterogeneous keys, which means that keys can be of any type and each key can be of a different type:
1330 |
1331 | ```clj
1332 | (let [m {:a 1, 1 :b, [1 2 3] "4 5 6"}]
1333 | [(get m :a) (get m [1 2 3])])
1334 | ;=> [1 "4 5 6"]
1335 |
1336 | ;;which can also be written without 'get', using map as a function of its keys:
1337 | (let [m {:a 1, 1 :b, [1 2 3] "4 5 6"}]
1338 | [(m :a) (m [1 2 3])])
1339 | ;=> [1 "4 5 6"]
1340 | ```
1341 |
1342 | Providing a map to a `seq` function returns a sequence of map entries:
1343 |
1344 | ```clj
1345 | (seq {:a 1, :b 2})
1346 | ;=> ([:a 1] [:b 2]) ;returns key/value pairs contained in vectors
1347 | ```
1348 |
1349 | A new hash map can be created idiomatically using `into`:
1350 |
1351 | ```clj
1352 | (into {} [[:a 1] [:b 2]])
1353 | ;=> {:a 1, :b 2}
1354 |
1355 | ;;even if pairs aren't vectors, they can easily be made to be
1356 | ;;here, the map function, that has nothing to do with map-the-data-structure,
1357 | ;;applies 'vec' to all the elements:
1358 | (into {} (map vec '[(:a 1) (:b 2)]))
1359 | ;=> {:a 1, :b 2}
1360 | ```
1361 |
1362 | If the key/value pairs are laid out in a sequence consecutively, your pairs don't even have to be explicitly grouped. You can use `apply` to create a hash map:
1363 |
1364 | ```clj
1365 | (apply hash-map [:a 1 :b 2])
1366 | ;=> {:a 1, :b 2}
1367 | ```
1368 |
1369 | Another idiomatic way to build a map is to use `zipmap` to "zip" together two sequences, the first of which contains keys and the second one values:
1370 |
1371 | ```clj
1372 | (zipmap [:a :b] [1 2])
1373 | ;=> {:b 2, :a 1}
1374 | ```
1375 |
1376 | `assoc` "adds" an element to a map:
1377 |
1378 | ```clj
1379 | (assoc {:bolts 1088} :camshafts 3)
1380 | ;=> {:camshafts 3, :bolts 1088}
1381 | ```
1382 |
1383 | `assoc` adds keys if they are not present, and replaces values if they are already there. If you associate a value onto `nil`, it creates a new map:
1384 |
1385 | ```clj
1386 | (assoc nil 5 2)
1387 | ;=> {5 2}
1388 | ```
1389 |
1390 | `merge` yields a map containing all the elements of all given maps, preferring the values from later ones:
1391 |
1392 | ```clj
1393 | (merge {:a 1, :b 2} {:b 3, :c 4})
1394 | ;=> {:c 4, :a 1, :b 3}
1395 | ```
1396 |
1397 | Remove map element with `dissoc`:
1398 |
1399 | ```clj
1400 | (dissoc {:a 1, :b 2, :c 4} :c)
1401 | ;=> {:a 1, :b 2}
1402 | ```
1403 |
1404 | **Sorted maps**
1405 |
1406 | The function `sorted-map` builds a map sorted by the comparison of its keys:
1407 |
1408 | ```clj
1409 | (sorted-map :b 1 :a 2 :c 0)
1410 | ;=> {:a 2, :b 1, :c 0}
1411 | ```
1412 |
1413 | If you need alternative key ordering, or ordering for keys that are not naturally comparable, use `sorted-map-by`, which allows you to provide a comparison function:
1414 |
1415 | ```clj
1416 | (sorted-map-by #(compare %1 %2) "bac" 9 "abc" 2)
1417 | ;=> {"abc" 2, "bac" 9}
1418 |
1419 | ;;Explanation:
1420 | ;; by doing this:
1421 | #(compare %1 %2) ;%1 stands for first parameter, in our case first map element
1422 |
1423 | ;; we declared an anonymous function inline, which is the same as writing:
1424 | (defn m-compare [first second]
1425 | (compare first second))
1426 |
1427 | ;; and then passing that function to sorted-by-map:
1428 | (sorted-map-by m-compare "bac" 9 "abc" 2)
1429 | ;=> {"abc" 2, "bac" 9}
1430 | ```
1431 |
1432 | Sorted maps (and sets) support efficient jump to a particular key and walk forward or backward from there through the collection. This is where `subseq` and `rsubseq` come in:
1433 |
1434 | ```clj
1435 | (def sm (sorted-map :a 1, :b 2, :c 3, :d 4, :e 5, :f 6, :g 7))
1436 |
1437 | (subseq sm > :e)
1438 | ;=> ([:f 6] [:g 7])
1439 |
1440 | (subseq sm > :c < :f)
1441 | ;=> ([:d 4] [:e 5])
1442 | ```
1443 |
1444 | There's one important difference in how sorted maps and sets handle numeric keys. A number can be represented by different types (`long`, `int`, `float`,...) and in a hash map, those types are preserved, while in a sorted map all those types are converted to the most precise one:
1445 |
1446 | ```clj
1447 | (assoc {1 :int} 1.0 :float)
1448 | ;=> {1.0 :float, 1 :int}
1449 |
1450 | (assoc (sorted-map 1 :int) 1.0 :float) ;only one is kept, since maps are unique
1451 | ;=> {1 :float}
1452 | ```
1453 |
1454 | When we're adding an element to a sorted map (or set), Clojure uses equality to determine both, the sort order and key presence (remember, maps have unique keys).
1455 |
1456 | **Array maps**
1457 |
1458 | Array maps are used to guarantee that the order of insertions will be preserved (just like vectors and arrays do):
1459 |
1460 | ```clj
1461 | (hash-map :a 1, :b 2, :c 3)
1462 | {:a 1, :c 3, :b 2}
1463 |
1464 | (array-map :a 1, :b 2, :c 3)
1465 | {:a 1, :b 2, :c 3}
1466 | ```
1467 |
1468 | > Like vectors, any item in a map literal is evaluated before the result is stored in the map. Unlike vectors, the order in which they are evaluated isn't guaranteed.
1469 |
1470 | ## Persistence, immutability and functional programming
1471 |
1472 | We'll start this section by giving a couple of phrases that encapsulate Clojure's immutability principles.
1473 |
1474 | > if two objects aren't equal forever, then they're technically never equal
1475 |
1476 | > there's a difference between a mutable object and a mutable reference. The default in Java is that there are references that may point to mutable data, but in Clojure, there are only mutable references
1477 |
1478 | > immutable objects are always thread safe (Brian Goetz)
1479 |
1480 | **Structural sharing**
1481 |
1482 | ```clojure
1483 | (def baselist (list :barnabas :adam))
1484 |
1485 | (def lst1 (cons :willie baselist))
1486 |
1487 | (def lst2 (cons :phoenix baselist))
1488 |
1489 | baselist
1490 | ;=> (:barnabas :adam) ;baselist stays unchanged
1491 |
1492 | lst1
1493 | ;=> (:willie :barnabas :adam)
1494 |
1495 | lst2
1496 | ;=> (:phoenix :barnabas :adam)
1497 |
1498 | (= (next lst1) (next lst2)) ;they are not only equal
1499 | ;=> true
1500 |
1501 | (identical? (next lst1) (next lst2)) ;but also the same underlying object
1502 | ;=> true
1503 | ```
1504 |
1505 | You can think of `baselist` as a common historical version of `lst1` and `lst2`, but it's also the shared part of both lists. Not only are the `next` parts of both lists equal, they are identical (the same instance in memory).
1506 |
1507 | Unlike lists, vectors and maps allow changes anywhere in the collection, not just on one end. This is made possible by the underlying data structure that those collection types are built upon - a tree.
1508 |
1509 | A tree allows interior changes and still maintains shared structure between different versions/changes.
1510 |
1511 | To demonstrate how _structural sharing_ works, we'll build a simple tree, where each node will have three fields: a value, a left branch and a right branch:
1512 |
1513 | ```clojure
1514 | {:val 50, :L nil, :R nil}
1515 | ```
1516 |
1517 | Our empty tree will be represented by `nil` and the map above will represent that empty tree after a single node (with value `50`) has been added.
1518 |
1519 | Let's start slowly. To handle just this initial case of adding a single node to an empty tree, we'll write `xconj` function like this:
1520 |
1521 | ```clj
1522 | (defn xconj [t v] ;add item with value 'v' to tree 't'
1523 | (cond
1524 | (nil? t) {:val v, :L nil, :R nil})) ;if t is nil this will be the first node (root)
1525 |
1526 | (xconj nil 50)
1527 | ;=> {:val 50, :L nil, :R nil}
1528 | ```
1529 |
1530 | OK, that works, but let's not start sucking each others' dicks just yet (TMMr Wolf). We need to handle the case of adding an item to a non-empty tree.
1531 |
1532 | So our tree doesn't even look like a tree yet:
1533 |
1534 |
1535 |
1536 | `:L` and `:R` are `nil`, so, for the sake of simplicity, we'll just make a rule that if an element does not point to some other element, it means it is `nil`. Presented this way, our tree looks like a piece of crap:
1537 |
1538 |
1539 |
1540 | When adding a node to a non-empty tree, in order to keep the tree sorted, we must follow a simple rule: _the value of any node in our tree must be greater than its left child and smaller or equal to its right child._
1541 |
1542 | So, in order to honor that rule, we need to compare the value being added first with the root, then with other nodes, down the tree, until we find the appropriate place for it.
1543 |
1544 | Let's try adding a couple of elements. How would we add value `40` to our tree?
1545 |
1546 |
1547 |
1548 | Now that you saw this crucial image, take a look at the next one (let's keep our `nil`s a bit longer, it will be easier to reason about the algorithm):
1549 |
1550 |
1551 |
1552 | How on earth did element `40` ended up there?
1553 |
1554 |
1555 | ```clj
1556 | (defn xconj [t v]
1557 | (cond
1558 | (nil? t) {:val v, :L nil, :R nil} ;does tree exist?
1559 | (< v (:val t)) ;if v is smaller than the current item's value
1560 | {:val (:val t), ;make new item whose value is the value of current item
1561 | :L (xconj (:L t) v), ;point :L to new tree by calling xconj on tree's :L child
1562 | :R (:R t)} ;point :R to current item's :R
1563 | :else {:val (:val t)
1564 | :L (:L t)
1565 | :R (xconj (:R t) v)}
1566 | ))
1567 |
1568 |
1569 | (defn xseq [t]
1570 | (when t
1571 | (concat (xseq (:L t)) [(:val t)] (xseq (:R t)))))
1572 |
1573 | ;;what is 'cond'?
1574 | (doc cond)
1575 | ;=> -------------------------
1576 | ;=> clojure.core/cond
1577 | ;=> ([& clauses])
1578 | ;=> Macro
1579 | ;=> Takes a set of test/expr pairs. It evaluates each test one at a
1580 | ;=> time. If a test returns logical true, cond evaluates and returns
1581 | ;=> the value of the corresponding expr and doesn't evaluate any of the
1582 | ;=> other tests or exprs. (cond) returns nil.
1583 | ```
1584 |
1585 | This is how our tree looks like:
1586 |
1587 |
1588 |
1589 | This is how our tree would look like if it was balanced. Compare number of hops needed to find value `20`.
1590 |
1591 |
1592 |
1593 |
1594 | > persistent collections are immutable, in-memory (not on-disk) collections that allow you to preserve historical versions of their state.
1595 |
1596 | Since arrays are mutable, any changes happen in-place:
1597 |
1598 | ```clj
1599 | (def ds (into-array [:frane :luka :glupaca])) ;mutable
1600 | ;=> #'mbo/ds
1601 |
1602 | ;; btw Glupaca is the name of our cat (which means something like "stupid women")
1603 |
1604 | (seq ds) ;only for nice REPL printout
1605 | ;=> (:frane :luka :glupaca)
1606 |
1607 | (aset ds 2 :suzi) ;replace third element of the array
1608 | ;=> :suzi
1609 |
1610 | (seq ds)
1611 | ;=> (:frane :luka :suzi)
1612 | ```
1613 |
1614 | Using one of Clojure's persistent data structures shows the difference:
1615 |
1616 | ```clj
1617 | mbo=> (def ds [:frane :luka :suzi]) ;init persistent collection
1618 | ;=> #'mbo/ds
1619 |
1620 | ds ;print ds to REPL
1621 | ;=> [:frane :luka :suzi]
1622 |
1623 | (def ds8 (replace {:suzi :glupaca} ds)) ;replace third element and bind the
1624 | ;=> #'mbo/ds8 ;new collection to ds8
1625 |
1626 | ds ;ds did not change
1627 | ;=> [:frane :luka :suzi]
1628 |
1629 | ds8 ;the newly created collection
1630 | ;=> [:frane :luka :glupaca]
1631 | ```
1632 |
1633 | # Symbols
1634 |
1635 | Closest thing to a variable in Clojure. Primarily used to provide a name for a given value, i.e. to refer to function parameters, local variables, globals, and Java classes.
1636 |
1637 | Unlike keywords, symbols are not unique based solely on their names:
1638 |
1639 | ```clj
1640 | (identical? 'node 'node)
1641 | ;=> false
1642 |
1643 | ;; identical? returns true only if symbols are the same object
1644 | (let [x 'node y x] (identical? x y))
1645 | ;=> true
1646 | ```
1647 |
1648 | Each `node` symbol is a discrete object that only happens to share a name. Though name is the basis for symbol equality:
1649 |
1650 | ```clj
1651 | (= 'node 'node)
1652 | ;=> true
1653 |
1654 | (name 'node)
1655 | ;=> "node"
1656 | ```
1657 |
1658 | We can define a meaning for a symbol within a specific expression, using `let`.
1659 | The `let` expression first **takes a vector of bindings**: alternating symbols and values that those symbols are bound to within the remainder of the expression.
1660 |
1661 | “Let the symbol `cats` be `5`, and construct a string composed of `"I have "`, `cats`, and `" cats"`:
1662 |
1663 | ```clj
1664 | (let [cats 5] (str "I have " cats " cats."))
1665 | ;=> "I have 5 cats."
1666 | ```
1667 |
1668 | Let bindings, also called **locals**, apply only within the `let` expression itself. They also override any existing definitions for symbols at that point in the program. For example, we can redefine addition to mean subtraction, for the duration of a `let`:
1669 |
1670 | ```clj
1671 | (let [+ -] (+ 2 3))
1672 | ;=> -1
1673 | ```
1674 |
1675 | That definition does not apply outside the `let`:
1676 |
1677 | ```clj
1678 | (+ 2 3)
1679 | ;=> 5
1680 | ```
1681 |
1682 | We can also provide multiple bindings. Since Clojure doesn’t care about spacing, alignment, or newlines, we’ll write this on multiple lines, for clarity:
1683 |
1684 | ```clj
1685 | (let [person "joseph"
1686 | num-cats 186]
1687 | (str person " has " num-cats " cats!")) ;the body
1688 | ;=> "joseph has 186 cats!"
1689 | ```
1690 |
1691 | When multiple bindings are given, they are evaluated in order. Later bindings can use previous bindings:
1692 |
1693 | ```clj
1694 | (let [cats 3
1695 | legs (* 4 cats)]
1696 | (str legs " legs all together"))
1697 | ;=> "12 legs all together"
1698 | ```
1699 |
1700 | > a symbol whose name is prefixed with a namespace, followed by a slash, is called **fully qualified symbol**:
1701 |
1702 | ```clj
1703 | clojure.core/map
1704 | ;=> #
1705 |
1706 | clojure.set/union
1707 | ;=> #
1708 | ```
1709 |
1710 | The body is sometimes described as an _implicit do_ (see [blocks bellow](#blocks)) because it follows the same rules: you may include any number of expressions and all will be evaluated, but only the value of the last one is returned.
1711 |
1712 | Because they’re immutable, _locals_ can’t be used to accumulate results. Instead,
1713 | you'd use a high level function or loop/recur form.
1714 |
1715 | To summarize, `let` defines the meaning of symbols within an expression. When Clojure evaluates a `let`, it replaces all occurrences of those symbols in the rest of the `let` expression with their corresponding values, then evaluates the rest of the expression.
1716 |
1717 | **Metadata**
1718 |
1719 | Clojure allows the attachment of metadata to various objects, including symbols. `with-meta` function takes an object and a map and returns another object of the same type with the metadata attached:
1720 |
1721 | ```clj
1722 | (let [x (with-meta 'node {:js true}) ;attach :js to 'node and assign to x
1723 | y (with-meta 'node {:js false})]
1724 | [(= x y) ;true because they both hold the same symbol, 'node
1725 | (identical? x y) ;false because they are different instances
1726 | (meta x)
1727 | (meta y)])
1728 | ;=> [true false {:js true} {:js false}]
1729 | ```
1730 |
1731 | **Symbols and namespaces**
1732 |
1733 | Like keywords, symbols don't belong to any specific namespace:
1734 |
1735 | ```clj
1736 | user=> (ns what-where)
1737 | ;=> nil
1738 |
1739 | what-where=> (def one-simbol 'where-is-it)
1740 | ;=> #'what-where/one-simbol
1741 |
1742 | what-where=> one-simbol
1743 | ;=> where-is-it
1744 |
1745 | what-where=> (resolve 'one-simbol)
1746 | ;=> #'what-where/one-simbol ;looks like namespace-qualified symbol
1747 | ;but it's just a characteristic of symbol evaluation
1748 |
1749 | what-where=> `one-symbol ;back tick
1750 | ;=> what-where/one-symbol
1751 | ```
1752 |
1753 | # Functions
1754 |
1755 | Functions are a first-class type in Clojure. They can be used the same as any value (stored in Vars, held in collections, passed as arguments and returned as a result of other functions).
1756 |
1757 | ```clj
1758 | (let [x] (+ x 1))
1759 | ```
1760 |
1761 | We can’t actually evaluate this program, because there’s no value for `x` yet. It could be `1`, or `4`, or `1453`. We say that `x` is _unbound_, because it has no binding to a particular value. This is the nature of the __function__: an expression with unbound symbols.
1762 |
1763 | Function definition:
1764 |
1765 | ```clj
1766 | (fn [x] (+ x 1))
1767 | ;=> #
1768 | ```
1769 |
1770 | Named function definition:
1771 |
1772 | ```clj
1773 | (let [twice (fn [x] (* 2 x))]
1774 | (+ (twice 1)
1775 | (twice 3)))
1776 | ;=> 8
1777 | ```
1778 |
1779 | `let` bindings describe a similar relationship, but with a specific set of values for those arguments. `let` is evaluated immediately, whereas `fn` is evaluated later, when bindings are provided.
1780 |
1781 | ## Vars
1782 |
1783 | Once a `let` is defined, there’s no way to change it. If we want to redefine symbols for everyone, even code that we didn’t write, we need a new construct, a mutable variable.
1784 |
1785 | ```clj
1786 | (def cats 5)
1787 | ;=> #'user/cats
1788 |
1789 | (type #'user/cats)
1790 | ;=> clojure.lang.Var
1791 |
1792 | cats
1793 | ;=> 5
1794 | ```
1795 |
1796 | `def` defines a type of value we haven’t seen before: a _Var_. _Vars_, like symbols, are references to other values. When evaluated, a _Var_ is replaced by its corresponding value.
1797 |
1798 | `def` also binds the symbol `cats` (and its globally qualified equivalent `user/cats`) to that _Var_.
1799 |
1800 | The symbol `inc` points to the _Var_ `#'inc`, which in turn points to the function `#`.
1801 |
1802 | We can see the intermediate Var with `resolve`:
1803 |
1804 | ```clj
1805 | 'inc ;symbol
1806 | ;=> inc
1807 |
1808 | (resolve 'inc)
1809 | ;=> #'clojure.core/inc ;variable
1810 |
1811 | (eval 'inc)
1812 | ;=> # ;value
1813 | ```
1814 |
1815 | Why those two levels of indirection? Unlike with symbol, we can change the meaning of a Var for everyone, globally, at any time.
1816 |
1817 | Vars don't require a value. Instead we can just declare them and, by doing so, defer the binding of value.
1818 |
1819 | ```clj
1820 | (def y)
1821 | ;=> #'user/y
1822 |
1823 | ;; if we try to use it:
1824 | y
1825 |
1826 | ;=> java.lang.IllegalStateException: Var user/y is unbound
1827 | ```
1828 |
1829 | ## Named functions
1830 |
1831 | ```clj
1832 | (def half
1833 | (fn [number] (/ number 2)))
1834 | ;=> #'user/half
1835 |
1836 | (half 8)
1837 | ;=> 4
1838 | ```
1839 |
1840 | Creating a function and binding it to a variable is so common that it has its own form: `defn`, which is a _macro_ that is short for `def fn`:
1841 |
1842 | ```clj
1843 | (defn half [number] (/ number 2))
1844 | ;=> #'user/half
1845 |
1846 | (half 8)
1847 | ;=> 4
1848 | ```
1849 |
1850 | Functions don’t have to take an argument. We’ve seen functions which take zero arguments, like `(+)`:
1851 |
1852 | ```clj
1853 | (defn half [] 1/2)
1854 | ;=> #'user/half
1855 | ```
1856 |
1857 | But if we try to use our earlier form with one argument, Clojure complains that the *arity* (the number of arguments to a function) is incorrect:
1858 |
1859 | ```clj
1860 | (half 8)
1861 |
1862 | ;=> ArityException Wrong number of args (1) passed to: user$half
1863 | ;=> clojure.lang.AFn.throwArity (AFn.java:437)
1864 | ```
1865 |
1866 | To handle multiple arities, functions have an alternate form, instead of an argument vector and a body, one provides a series of lists, each of which starts with an argument vector, followed by the body:
1867 |
1868 | ```clj
1869 | (defn half
1870 | ([] 1/2)
1871 | ([x] (/ x 2)))
1872 | ;=> #'user/half
1873 |
1874 | (half)
1875 | ;=> 1/2
1876 |
1877 | (half 8)
1878 | ;=> 4
1879 | ```
1880 |
1881 | Multiple arguments work just like you expect. Just specify an argument vector of two, or three, or however many arguments the function takes.
1882 | Some functions can take any number of arguments. For that, Clojure provides `&`, which slurps up all remaining arguments as a list:
1883 |
1884 | ```clj
1885 | (defn vargs [x y & more-args]
1886 | {:x x
1887 | :y y
1888 | :more more-args})
1889 | ;=> #'user/vargs
1890 |
1891 | (vargs 1 2)
1892 | ;=> {:x 1, :y 2, :more nil}
1893 |
1894 | (vargs 1 2 3 4 5)
1895 | ;=> {:x 1, :y 2, :more (3 4 5)}
1896 | ```
1897 |
1898 | `x` and `y` are mandatory, though there don’t have to be any remaining arguments.
1899 |
1900 | To keep track of what arguments a function takes, why the function exists, and what it does, we usually include a **docstring**. Docstrings help fill in the missing context around functions, to explain their assumptions, context, and purpose to the world:
1901 |
1902 | ```clj
1903 | (defn launch
1904 | "Launches a spacecraft into the given orbit by initiating a
1905 | controlled on-axis burn. Does not automatically stage, but
1906 | does vector thrust, if the craft supports it."
1907 | [craft target-orbit]
1908 | "OK, we don't know how to control spacecraft yet.")
1909 | ;=> #'user/launch
1910 | ```
1911 |
1912 | Docstrings are used to automatically generate documentation for a Clojure programs, but you can also access them from the **REPL** (The `user=>` prompt refers to the top-level namespace of the default REPL):
1913 |
1914 | ```clj
1915 | (doc launch)
1916 | ;=> -------------------------
1917 | ;=> user/launch
1918 | ;=> ([craft target-orbit])
1919 | ;=> Launches a spacecraft into the given orbit by initiating a
1920 | ;=> controlled on-axis burn. Does not automatically stage, but
1921 | ;=> does vector thrust, if the craft supports it.
1922 | ;=> nil
1923 | ```
1924 |
1925 | `doc` tells us the full name of the function, the arguments it accepts, and its docstring. This information comes from the `launch` Var’s metadata, and is saved there by `defn`. We can inspect metadata directly with the `meta` function:
1926 |
1927 | ```clj
1928 | (meta #'launch)
1929 | ;=> {:arglists ([craft target-orbit]), :ns #, :name launch, :column 1,
1930 | ;=> :doc "Launches a spacecraft into the given orbit by initiating a\n controlled
1931 | ;=> on-axis burn. Does not automatically stage, but\n does vector thrust, if the
1932 | ;=> craft supports it.", :line 1, :file "/tmp/form-init523009510157887861.clj"}
1933 | ```
1934 |
1935 | There’s some other juicy information in there, like the file the function was defined in and which line and column it started at, but that’s not particularly useful since we’re in the _REPL_, not a file. However, this does hint at a way to answer our motivating question: how does the `type` function work?
1936 |
1937 | ## Blocks
1938 |
1939 | When you have a series or block of expressions that need to be treated as one, use `do`. All the expressions will be evaluated, but only the last one will be returned:
1940 |
1941 | ```clj
1942 | (do
1943 | 6
1944 | (+ 5 4)
1945 | 3)
1946 | ;=> 3
1947 | ```
1948 |
1949 | The expressions `6` and `(+ 5 4)` are perfectly legal. The addition in `(+ 5 4)` is even done, but the value is thrown away, only the final expression `3` is returned.
1950 |
1951 | ## How does `type` work?
1952 |
1953 | `type`, like all functions, is a kind of object with its own unique type:
1954 |
1955 | ```clj
1956 | type
1957 | ;=> #
1958 |
1959 | (type type)
1960 | ;=> clojure.core$type
1961 | ```
1962 |
1963 | This tells us that `type` is a particular instance, at memory address `39bda9b9`, of the type `clojure.core$type`.
1964 | `clojure.core` is a namespace which defines the fundamentals of the Clojure language, and `$type` tells us that it’s named type in that namespace. None of this is particularly helpful, though. Maybe we can find out more about the `clojure.core$type` by asking what its supertypes are:
1965 |
1966 | ```clj
1967 | (supers (type type))
1968 | ;=> #{java.io.Serializable java.lang.Runnable clojure.lang.AFunction
1969 | ;=> clojure.lang.IMeta clojure.lang.AFn java.lang.Object clojure.lang.IObj
1970 | ;=> java.util.Comparator clojure.lang.Fn java.util.concurrent.Callable
1971 | ;=> clojure.lang.IFn}
1972 | ```
1973 |
1974 | This is a set of all the types that include `type`. We say that `type` is an instance of `clojure.lang.AFunction`, or that it implements or extends `java.util.concurrent.Callable`, and so on. Since it’s a member of `clojure.lang.IMeta` it has metadata, and since it’s a member of `clojure.lang.AFn`, it’s a function. Just to double check, let’s confirm that `type` is indeed a function:
1975 |
1976 | ```clj
1977 | (fn? type)
1978 | ;=> true
1979 | ```
1980 |
1981 | `type` can take a single argument, which it calls `x`. If it has `:type` metadata, that’s what it returns. Otherwise, it returns the class of `x`. Let’s take a deeper look at `type`’s metadata for more clues:
1982 |
1983 | ```clj
1984 | (doc type)
1985 | ;=> -------------------------
1986 | ;=> clojure.core/type
1987 | ;=> ([x])
1988 | ;=> Returns the :type metadata of x, or its Class if none
1989 | ;=> nil
1990 | ```
1991 |
1992 | This function was first added to Clojure in version `1.0`, and is defined in the file `clojure/core.clj`, on line `3109`:
1993 |
1994 | ```clj
1995 | (meta #'type)
1996 | ;=> {:ns #, :name type, :arglists ([x]), :column 1,
1997 | ;=> :added "1.0", :static true, :doc "Returns the :type metadata of x, or its Class
1998 | ;=> if none", :line 3109, :file "clojure/core.clj"}
1999 | ```
2000 |
2001 | We could go dig up the Clojure source code and read its definition there, or we could ask Clojure to do it for us. Aha! Here, at last, is how `type` works. It’s a function which takes a single argument `x`, and returns either `:type` from its metadata, or `(class x)`.
2002 |
2003 | ```clj
2004 | (source type)
2005 | ;=> (defn type
2006 | ;=> "Returns the :type metadata of x, or its Class if none"
2007 | ;=> {:added "1.0"
2008 | ;=> :static true}
2009 | ;=> [x]
2010 | ;=> (or (get (meta x) :type) (class x)))
2011 | ;=> nil
2012 | ```
2013 |
2014 | # Sequences
2015 |
2016 | A **sequential** collection is one that holds a series of values without reordering them.
2017 |
2018 | A **sequence** is a sequential collection that represents a series of values that may or may not exist yet (may have concrete values, may be lazy or empty). Few composite types are actually _sequences_, though several such as vectors are _sequential_. All an object needs to do to be a sequence is to support two core functions, `first` and `rest`
2019 |
2020 | A **seq** is a simple API for navigating collections which consists of two functions, `first` and `rest`
2021 |
2022 | If two sequentials have the same values in the same order, `=` will return `true` for them, even if their concrete types are different:
2023 |
2024 | ```clj
2025 | (= [1 2 3] '(1 2 3))
2026 | ;=> true
2027 | ```
2028 |
2029 | Conversely, even if two collections have the same values in the same order, if one is a sequential collection and the other isn't, `=` will return `false`:
2030 |
2031 | ```clj
2032 | (= [1 2 3] #{1 2 3})
2033 | ;=> false
2034 | ```
2035 |
2036 | If the collection is empty, `seq` always returns `nil` and never an empty sequence (that goes for all other functions that return a `seq`, e.g. `next`).
2037 |
2038 | > Clojure classifies each composite data type into 3 partitions: _sequentials_, _maps_ and _sets_. Everything that implements `java.util.List` is included in the sequential partition. Generally things that fall into other two partitions include set or map in their name
2039 |
2040 | Every collection type provides at least one kind of `seq` object for walking through its elements
2041 |
2042 | ## Recursion
2043 |
2044 | `cons`, makes a list beginning with the first argument, followed by all the elements in the second argument:
2045 |
2046 | ```clj
2047 | (cons 1 [2 3 4])
2048 | ;=> (1 2 3 4)
2049 | ```
2050 |
2051 | Problem of incrementing all elements of a vector:
2052 |
2053 | ```clj
2054 | (defn inc-first [nums]
2055 | (if (first nums)
2056 | ; If there's a first num, build a new list with cons
2057 | (cons (inc (first nums))
2058 | (rest nums))
2059 | ; If there's no first num, return an empty list
2060 | (list)))
2061 | ;=> #'user/inc-first
2062 |
2063 | (inc-first [])
2064 | ;=> ()
2065 |
2066 | (inc-first [1 2 3])
2067 | ;=> (2 2 3)
2068 | ```
2069 |
2070 | What if we called our function on `rest`?
2071 |
2072 | ```clj
2073 | (defn inc-all [nums]
2074 | (if (first nums)
2075 | (cons (inc (first nums))
2076 | (inc-all (rest nums)))
2077 | (list)))
2078 | ;=> #'user/inc-all
2079 |
2080 | (inc-all [1 2 3 4])
2081 | ;=> (2 3 4 5)
2082 | ```
2083 |
2084 | This technique is called _recursion_, and it is a fundamental principle in working with collections, sequences, trees, graphs or any problem which has small parts linked together. There are two key elements in a recursive program:
2085 | - Some part of the problem which has a known solution
2086 | - A relationship which connects one part of the problem to the next
2087 |
2088 | Incrementing the elements of an empty list returns the empty list. This is our **base case**, the ground to build on. Our **inductive case**, also called the _recurrence relation_, is how we broke the problem up into incrementing the first number in the sequence, and incrementing all the numbers in the rest of the sequence. The `if` expression bound these two cases together into a single function, a function defined in terms of itself.
2089 | Let’s parameterize our `inc-all` function to use any transformation of its elements:
2090 |
2091 | ```clj
2092 | (defn transform-all [f xs]
2093 | (if (first xs)
2094 | (cons (f (first xs))
2095 | (transform-all f (rest xs)))
2096 | (list)))
2097 | ;=> #'user/transform-all
2098 |
2099 | (transform-all inc [1 2 3 4])
2100 | ;=> (2 3 4 5)
2101 | ```
2102 |
2103 | ## Loop
2104 |
2105 | When using recursion, you sometimes want to loop back not to the top of the function, but to somewhere inside the function body.
2106 | The `loop` acts exactly like `let` but provides a target for `recur` to jump to:
2107 |
2108 | ```clj
2109 | (defn sum-down-from [initial-x]
2110 | (loop [sum 0, x initial-x]
2111 | (if (pos? x)
2112 | (recur (+ sum x) (dec x))
2113 | sum)))
2114 | ;=> #'user/sum-down-from
2115 | ```
2116 |
2117 | Upon entering the `loop`, the locals `sum` and `x` are initialized (like in `let`). A `recur` always loops back to the closest enclosing `loop` or `fn`. The `loop` locals are rebound to the values given in `recur`.
2118 | `recur` works only from the tail position.
2119 |
2120 | `keyword` transforms a string to keyword:
2121 |
2122 | ```clj
2123 | (transform-all keyword ["aa" "bb" "cc"])
2124 | ;=> (:aa :bb :cc)
2125 | ```
2126 |
2127 | To wrap every element in a list:
2128 |
2129 | ```clj
2130 | (transform-all list ["aa" "bb" "cc"])
2131 | ;=> (("aa") ("bb") ("cc"))
2132 | ```
2133 |
2134 | We basically implemented `map` function:
2135 |
2136 | ```clj
2137 | (map inc [1 2 3 4])
2138 | ;=> (2 3 4 5)
2139 | ```
2140 |
2141 | The function `map` relates one sequence to another. The type `map` relates keys to values. There is a deep symmetry between the two: maps are usually sparse, and the relationships between keys and values may be arbitrarily complex. The `map` function, on the other hand, usually expresses the same type of relationship, applied to a series of elements in a fixed order.
2142 |
2143 | Clojure has a _special form_ called `recur` that's specifically used for tail recursion:
2144 |
2145 | ```clj
2146 | (defn print-down-from [x]
2147 | (when (pos? x) ;return when x is no longer positive
2148 | (println x)
2149 | (recur (dec x))))
2150 | ;=> #'user/print-down-from
2151 |
2152 | (print-down-from 5)
2153 | ;=> 5
2154 | ;=> 4
2155 | ;=> 3
2156 | ;=> 2
2157 | ;=> 1
2158 | ;=> nil
2159 | ```
2160 |
2161 | > `when` is same as `if`, except it doesn't have the `else` part and it provides an implicit `do` in order to perform side-effects
2162 |
2163 | This is nearly identical to how you’d structure a while loop in an imperative language. One significant difference is that the value of `x` isn’t decremented somewhere in the body of the loop. Instead, a new value is calculated as a parameter to `recur`, which immediately does two things: rebinds `x` to the new value and returns control to the top of `print-down-from`.
2164 | If the function has multiple arguments, the `recur` call must as well, just as if you were calling the function by name instead of using the `recur` special form. And just as with a function call, the expressions in the `recur` are evaluated in order first and only then bound to the function arguments simultaneously.
2165 |
2166 | ## Building Sequences
2167 |
2168 | We can use recursion to expand a single value into a sequence of values, each related by some function. For instance (`pos?` returns `true` if `num` is greater than zero, else `false`):
2169 |
2170 | ```clj
2171 | (defn expand [f x count]
2172 | (if (pos? count)
2173 | (cons x (expand f (f x) (dec count)))))
2174 | ;=> #'user/expand
2175 |
2176 | (expand inc 0 10)
2177 | ;=> (0 1 2 3 4 5 6 7 8 9)
2178 | ```
2179 |
2180 | Our base case is `x` itself, followed by the sequence beginning with `(f x)`. That sequence in turn expands to `(f (f x))`, and then to `(f (f (f x)))`, and so on. Each time we call `expand`, we count down by one using `dec`. Once the `count` is zero, `if` returns `nil`, and evaluation stops.
2181 |
2182 | Clojure has a more general form of this function, called `iterate`:
2183 |
2184 | ```clj
2185 | (take 10 (iterate inc 0))
2186 | ;=> (0 1 2 3 4 5 6 7 8 9)
2187 | ```
2188 |
2189 | Since this sequence is infinitely long, we’re using `take` to select only the first 10 elements. We can construct more complex sequences by using more complex functions:
2190 |
2191 | ```clj
2192 | (take 10 (iterate (fn [x] (if (odd? x) (+ 1 x) (/ x 2))) 10))
2193 | ;=> (10 5 6 3 4 2 1 2 1 2)
2194 | ```
2195 |
2196 | `repeat` constructs a sequence where every element is the same:
2197 |
2198 | ```clj
2199 | (take 10 (repeat "a"))
2200 | ;=> ("a" "a" "a" "a" "a" "a" "a" "a" "a" "a")
2201 |
2202 | (repeat 5 "b")
2203 | ;=> ("b" "b" "b" "b" "b")
2204 | ```
2205 |
2206 | `repeatedly` simply calls a function `(f)` to generate an infinite sequence of values, over and over again, without any relationship between elements. For an infinite sequence of random numbers:
2207 |
2208 | ```clj
2209 | (rand)
2210 | ;=> 0.6934524557647231
2211 |
2212 | (rand)
2213 | ;=> 0.1355414232605504
2214 |
2215 | (take 3 (repeatedly rand))
2216 | ;=> (0.18806021884865332 0.5231673860825672 0.38244349544358525)
2217 | ```
2218 |
2219 | `range` generates a sequence of numbers between two points.
2220 | `(range n)` gives `n` successive integers starting at 0.
2221 | `(range n m)` returns integers from `n` to `m-1`.
2222 | `(range n m step)` returns integers from `n` to `m`, separated by `step`:
2223 |
2224 | ```clj
2225 | (range 5)
2226 | ;=> (0 1 2 3 4)
2227 |
2228 | (range 5 8)
2229 | ;=> (5 6 7)
2230 |
2231 | (range 5 25 5)
2232 | ;=> (5 10 15 20)
2233 | ```
2234 |
2235 | `cycle` returns an infinite lazy sequence of repetitions of the items in a collection:
2236 |
2237 | ```clj
2238 | (take 6 (cycle (range 5 50 5)))
2239 | ;=> (5 10 15 20 25 30)
2240 | ```
2241 |
2242 | ## Transforming Sequences
2243 |
2244 | `map` applies a function to each element, but it has a few more tricks up its sleeve:
2245 |
2246 | ```clj
2247 | (map (fn [n vehicle] (str "I've got " n " " vehicle "s"))
2248 | [0 200 9]
2249 | ["car" "train" "kiteboard"])
2250 | ;=> ("I've got 0 cars" "I've got 200 trains" "I've got 9 kiteboards")
2251 | ```
2252 |
2253 | If given multiple sequences, `map` calls its function with one element from each sequence in turn. So the first value will be `(f 0 "car")`, the second `(f 200 "train")`, and so on. Like a zipper, map folds together corresponding elements from multiple collections. To sum three vectors, column-wise:
2254 |
2255 | ```clj
2256 | (map + [1 2 3]
2257 | [4 5 6]
2258 | [3 2 1])
2259 | ;=> (8 9 10)
2260 | ```
2261 |
2262 | If one sequence is bigger than another, `map` stops at the end of the smaller one. We can exploit this to combine finite and infinite sequences. For example, to number the elements in a vector:
2263 |
2264 | ```clj
2265 | (map (fn [index element] (str index ". " element))
2266 | (iterate inc 0)
2267 | ["erlang" "scala" "haskell"])
2268 | ;=> ("0. erlang" "1. scala" "2. haskell")
2269 | ```
2270 |
2271 | Transforming elements together with their indices is so common that Clojure has a special function for it: `map-indexed`:
2272 |
2273 | ```clj
2274 | (map-indexed (fn [index element] (str index ". " element))
2275 | ["erlang" "scala" "haskell"])
2276 | ;=> ("0. erlang" "1. scala" "2. haskell")
2277 | ```
2278 |
2279 | You can also tack one sequence onto the end of another, like so:
2280 |
2281 | ```clj
2282 | (concat [1 2 3] [:a :b :c] [4 5 6])
2283 | ;=> (1 2 3 :a :b :c 4 5 6)
2284 | ```
2285 |
2286 | Another way to combine two sequences is to riffle them together, using `interleave`:
2287 |
2288 | ```clj
2289 | (interleave [:a :b :c] [1 2 3])
2290 | ;=> (:a 1 :b 2 :c 3)
2291 | ```
2292 |
2293 | And if you want to insert a specific element between each successive pair in a sequence, try `interpose`:
2294 |
2295 | ```clj
2296 | (interpose :and [1 2 3 4])
2297 | ;=> (1 :and 2 :and 3 :and 4)
2298 | ```
2299 |
2300 | To reverse a sequence, use ... you guessed it, `reverse`:
2301 |
2302 | ```clj
2303 | (reverse [1 2 3])
2304 | ;=> (3 2 1)
2305 |
2306 | (reverse "woolf")
2307 | ;=> (\f \l \o \o \w) ;not a string
2308 | ```
2309 |
2310 | Strings are sequences too! Each element of a string is a character, written `\f`. You can rejoin those characters into a string with `apply str`:
2311 |
2312 | ```clj
2313 | (apply str (reverse "woolf"))
2314 | ;=> "floow"
2315 | ```
2316 |
2317 | …and break strings up into sequences of chars with `seq`:
2318 |
2319 | ```clj
2320 | (seq "sato")
2321 | ;=> (\s \a \t \o)
2322 | ```
2323 |
2324 | To randomize the order of a sequence, use `shuffle`:
2325 |
2326 | ```clj
2327 | (shuffle [1 2 3 4 5])
2328 | ;=> [4 3 5 1 2]
2329 |
2330 | (apply str (shuffle (seq "abracadabra")))
2331 | ;=> "raradbabaac"
2332 | ```
2333 |
2334 | ## Subsequences
2335 |
2336 | `take` selects the first `n` elements, `drop` removes the first `n` elements, `take-last` and `drop-last` operate on the last `n` elements:
2337 |
2338 | ```clj
2339 | (take 3 (range 10))
2340 | ;=> (0 1 2)
2341 |
2342 | (drop 3 (range 10))
2343 | ;=> (3 4 5 6 7 8 9)
2344 |
2345 | (take-last 3 (range 10))
2346 | ;=> (7 8 9)
2347 |
2348 | (drop-last 3 (range 10))
2349 | ;=> (0 1 2 3 4 5 6)
2350 | ```
2351 |
2352 | `take-while` and `drop-while` work just like `take` and `drop`, but use a function to decide when to stop:
2353 |
2354 | ```clj
2355 | (take-while pos? [3 2 1 0 -1 -2 10])
2356 | ;=> (3 2 1)
2357 | ```
2358 |
2359 | In general, one can cut a sequence in twain by using `split-at` with a particular index. There’s also `split-with`, which uses a function to decide when to cut:
2360 |
2361 | ```clj
2362 | (split-at 4 (range 10))
2363 | ;=> [(0 1 2 3) (4 5 6 7 8 9)]
2364 |
2365 | (split-with number? [1 2 3 :mark 4 5 6 :mark 7])
2366 | ;=> [(1 2 3) (:mark 4 5 6 :mark 7)]
2367 | ```
2368 |
2369 | Notice that because indexes start at zero, sequence functions tend to have predictable number of elements.`(split-at 4)` yields four elements in the first collection, and ensures the second collection begins at index four. `(range 10)` has ten elements, corresponding to the first ten indices in a sequence. `(range 3 5)` has two (as in `5 - 3 = 2`) elements. These choices simplify the definition of recursive functions as well.
2370 | We can select particular elements from a sequence by applying a function. To pull up all positive numbers in a list, use `filter`:
2371 |
2372 | ```clj
2373 | (filter pos? [1 5 -4 -7 3 0])
2374 | ;=> (1 5 3)
2375 | ```
2376 |
2377 | `filter` looks at each element in turn, and includes it in the resulting sequence only if `(f element)` returns a _truthy_ value. Its complement is `remove`, which only includes those elements where `(f element)` is `false` or `nil`:
2378 |
2379 | ```clj
2380 | (remove string? [1 "tur" :apple])
2381 | ;=> (1 :apple)
2382 | ```
2383 |
2384 | One can group a sequence into chunks using `partition`, `partition-all`, or `partition-by`. For instance, one might group alternating values into pairs like this:
2385 |
2386 | ```clj
2387 | (partition 2 [:cats 5 :bats 27 :crocs 0])
2388 | ;=> ((:cats 5) (:bats 27) (:crocs 0))
2389 | ```
2390 |
2391 | Separate a series of numbers into negative and positive subsequences:
2392 |
2393 | ```clj
2394 | (partition-by neg? [1 2 3 2 1 -1 -2 -3 -2 -1 1 2])
2395 | ;=> ((1 2 3 2 1) (-1 -2 -3 -2 -1) (1 2))
2396 | ```
2397 |
2398 | `partition-all n collection` may include partitions with fewer than `n` items at the end:
2399 |
2400 | ```clj
2401 | (partition-all 3 [1 2 -5 3 2 1 -1 -2 -3 -2 -1 1 2])
2402 | ;=> ((1 2 -5) (3 2 1) (-1 -2 -3) (-2 -1 1) (2))
2403 | ```
2404 |
2405 | while `partition` may not:
2406 |
2407 | ```clj
2408 | (partition 3 [1 2 -5 3 2 1 -1 -2 -3 -2 -1 1 2])
2409 | ;=> ((1 2 -5) (3 2 1) (-1 -2 -3) (-2 -1 1))
2410 | ```
2411 |
2412 | ### Collapsing subsequences
2413 |
2414 | After transforming a sequence, we often want to collapse it in some way, in order to derive some smaller value. For instance, we might want the number of times each element appears in a sequence:
2415 |
2416 | ```clj
2417 | (frequencies [:meow :mrrrow :meow :meow])
2418 | ;=> {:meow 3, :mrrrow 1}
2419 | ```
2420 |
2421 | To group elements by some function:
2422 |
2423 | ```clj
2424 | (pprint (group-by :first [{:first "Li" :last "Zhou"}
2425 | {:first "Sarah" :last "Lee"}
2426 | {:first "Sarah" :last "Dunn"}
2427 | {:first "Li" :last "O'Toole"}]))
2428 | ;=> {"Li" [{:last "Zhou", :first "Li"} {:last "O'Toole", :first "Li"}],
2429 | ;=> "Sarah" [{:last "Lee", :first "Sarah"} {:last "Dunn", :first "Sarah"}]}
2430 | ```
2431 |
2432 | Here we’ve taken a sequence of people with first and last names, and used the `:first` keyword (which can act as a function!) to look up those first names. `group-by` used that function to produce a map of first names to lists of people, kind of like an index.
2433 | In general, we want to combine elements together in some way, using a function. Where `map` treated each element independently, reducing a sequence requires that we bring some information along. The most general way to collapse a sequence is `reduce`:
2434 |
2435 | ```clj
2436 | (doc reduce)
2437 | ;=> -------------------------
2438 | ;=> clojure.core/reduce
2439 | ;=> ([f coll] [f val coll])
2440 | ;=> f should be a function of 2 arguments. If val is not supplied,
2441 | ;=> returns the result of applying f to the first 2 items in coll, then
2442 | ;=> applying f to that result and the 3rd item, etc. If coll contains no
2443 | ;=> items, f must accept no arguments as well, and reduce returns the
2444 | ;=> result of calling f with no arguments. If coll has only 1 item, it
2445 | ;=> is returned and f is not called. If val is supplied, returns the
2446 | ;=> result of applying f to val and the first item in coll, then
2447 | ;=> applying f to that result and the 2nd item, etc. If coll contains no
2448 | ;=> items, returns val and f is not called.
2449 |
2450 | (reduce + [1 2 3 4])
2451 | ;=> 10
2452 |
2453 | (reduce + 1 [1 2 3 4])
2454 | ;=> 11
2455 | ```
2456 |
2457 | To see the reducing process in action, we can use `reductions`, which returns a sequence of all the intermediate states:
2458 |
2459 | ```clj
2460 | (reductions + [1 2 3 4])
2461 | ;=> (1 3 6 10)
2462 | ```
2463 |
2464 | Oftentimes we include a default state to start with. For instance, we could start with an empty set, and add each element to it as we go along:
2465 |
2466 | ```clj
2467 | (reduce conj #{} [:a :b :b :b :a :c])
2468 | ;=> #{:a :c :b}
2469 | ```
2470 |
2471 | Reducing elements into a collection has its own name: `into`. We can `conj [key value]` vectors into a map, for instance, or build up a list:
2472 |
2473 | ```clj
2474 | (into {} [[:a 2] [:b 3]])
2475 | ;=> {:a 2, :b 3}
2476 |
2477 | (into (list) [1 2 3 4])
2478 | ;=> (4 3 2 1)
2479 | ```
2480 |
2481 | Because **elements added to a list appear at the beginning**, not the end, this expression **reverses the sequence**. Vectors `conj` onto the end, so to emit the elements in order, using reduce, we might try:
2482 |
2483 | ```clj
2484 | (reduce conj [] [1 2 3 4 5])
2485 | ;=> [1 2 3 4 5]
2486 | ```
2487 |
2488 | Remember?
2489 |
2490 | ```clj
2491 | (conj [-1 0] [1 2 3 4 5])
2492 | ;=> [-1 0 [1 2 3 4 5]] ; not [-1 0 1 2 3 4 5]
2493 | ```
2494 |
2495 | This looks like a `map` function. All that’s missing is some kind of transformation applied to each element:
2496 |
2497 | ```clj
2498 | (defn my-map [f coll]
2499 | (reduce (fn [output element]
2500 | (conj output (f element)))
2501 | []
2502 | coll))
2503 | ;=> #'user/my-map
2504 |
2505 | (my-map inc [1 2 3 4])
2506 | ;=> [2 3 4 5]
2507 | ```
2508 |
2509 | So `map` is just a special kind of `reduce`. What about, say, `take-while`?
2510 |
2511 | ```clj
2512 | (defn my-take-while [f coll]
2513 | (reduce (fn [out elem]
2514 | (if (f elem)
2515 | (conj out elem)
2516 | (reduced out)))
2517 | []
2518 | coll))
2519 | ;=> #'user/my-take-while
2520 | ```
2521 |
2522 | We’re using a special function here, `reduced`, to indicate that we’ve completed our reduction early and can skip the rest of the sequence.
2523 |
2524 | ```clj
2525 | (my-take-while pos? [2 1 0 -1 0 1 2])
2526 | ;=> [2 1]
2527 | ```
2528 |
2529 | Most of Clojure’s **sequence functions are lazy**. For instance, we can increment every number from zero to infinity:
2530 |
2531 | ```clj
2532 | (def infseq (map inc (iterate inc 0)))
2533 | ;=> #'user/infseq
2534 |
2535 | (realized? infseq)
2536 | ;=> false
2537 | ```
2538 |
2539 | That function returned immediately. Because it hasn’t done any work yet, we say the sequence is unrealized. It doesn’t increment any numbers at all until we ask for them:
2540 |
2541 | ```clj
2542 | (take 10 infseq)
2543 | ;=> (1 2 3 4 5 6 7 8 9 10)
2544 |
2545 | (realized? infseq)
2546 | ;=> true
2547 | ```
2548 |
2549 | **Lazy sequences also remember their contents, once evaluated, for faster access.**
2550 |
2551 | Find the sum of the products of consecutive pairs of the first 1000 odd integers.
2552 |
2553 | ```clj
2554 | (reduce +
2555 | (take 1000
2556 | (map (fn [pair] (* (first pair) (second pair)))
2557 | (partition 2 1
2558 | (filter odd?
2559 | (iterate inc 0))))))
2560 | ;=> 1335333000
2561 | ```
2562 |
2563 | __Homework:__
2564 |
2565 | 1. Write a function to find out if a string is a palindrome.
2566 |
2567 | ```clj
2568 | (defn palindrome? [word]
2569 | (== 0 (compare word (apply str (reverse word)))))
2570 | ```
2571 |
2572 | 2. Find the number of `c`s in `“abracadabra”`.
2573 |
2574 | ```clj
2575 | (defn occurs-count [c word]
2576 | (get (frequencies (seq word)) c 0))
2577 | ```
2578 |
2579 | 3. Write your own version of `filter`.
2580 |
2581 | ```clj
2582 | ;=> TBD
2583 | ```
2584 |
2585 | # Java interop
2586 |
2587 | Clojure is _symbiotic_ with its host, providing its rich and powerful features, while Java provides an object model, libraries and runtime support.
2588 |
2589 | Clojure strings are Java `String`s, numbers are `Number`s, collections implement `Collection`, fns implement `Callable` and `Runnable`, ...
2590 |
2591 | Core abstractions, such as `seq`, are Java interfaces (`ISeq`).
2592 | Clojure `seq` library works on Java `Iterable`s, `String`s and arrays.
2593 | It is possible to implement and extend Java interfaces and classes.
2594 |
2595 | **Accessing static class members**
2596 |
2597 | ... is trivial:
2598 |
2599 | ```clj
2600 | java.util.Locale/JAPAN
2601 | ;=> #
2602 | ```
2603 |
2604 | Idiomatic Clojure prefers that you access static class members using a syntax like accessing a namespace-qualified Var:
2605 |
2606 | ```clj
2607 | (Math/sqrt 9) ; the same as (java.lang.Math/sqrt 9)
2608 | ;=> 3.0
2609 | ```
2610 |
2611 | **Creating Java class instances**
2612 |
2613 | ```clj
2614 | (new java.util.HashMap {"foo" 42 "bar" 8 "baz" "beep boop"})
2615 | ;=> {"baz" "beep boop", "foo" 42, "bar" 8}
2616 |
2617 | ;;idiomatic:
2618 | (java.util.HashMap. {"foo" 42 "bar" 8 "baz" "beep boop"}) ;dot = constructor call
2619 | ;=> {"baz" "beep boop", "foo" 42, "bar" 8}
2620 | ```
2621 |
2622 | **Accessing Java instance members with the dot operator**
2623 |
2624 | To access instance properties, precede the property or method name with a dot:
2625 |
2626 | ```clj
2627 | (.x (java.awt.Point. 10 20)) ;create a new Point and access its member x
2628 | ;=> 10
2629 | ```
2630 |
2631 | To access instance methods, the dot form allows an additional argument to be passed to the method:
2632 |
2633 | ```clj
2634 | (.divide (java.math.BigDecimal. "42") 2K)
2635 | ;=> 21M
2636 |
2637 | ; what's this M for?
2638 | (type 2M)
2639 | ;=> java.math.BigDecimal
2640 | ```
2641 |
2642 | **Setting Java instance properties**
2643 |
2644 | In the absence of mutator methods, in the form of `setX`, Java instance properties can be set using `set!` function:
2645 |
2646 | ```clj
2647 | (let [origin (java.awt.Point. 0 0)]
2648 | (set! (.x origin) 15) ;(set! )
2649 | (str origin))
2650 | ;=> "java.awt.Point[x=15,y=0]"
2651 | ```
2652 |
2653 | **The `..` macro**
2654 |
2655 | For now, think of a macro as a convenience function. We'll meet them [later](#macros).
2656 | In Java, it's a common practice to chain together a sequence of method calls, e.g:
2657 |
2658 | ```java
2659 | new java.util.Date().toString().endsWith("2014") ;java
2660 | ```
2661 |
2662 | ... which is equivalent to this Clojure expression:
2663 |
2664 | ```clj
2665 | (.endsWith (.toString (java.util.Date.)) "2014")
2666 | ;=> true
2667 | ```
2668 |
2669 | Well, anyone would agree that this is rather difficult to read.
2670 | To remedy this, Clojure provides us with `..` macro:
2671 |
2672 | ```clj
2673 | (.. (java.util.Date.) toString (endsWith "2014"))
2674 | ;=> true
2675 | ```
2676 |
2677 | **The `doto` macro**
2678 |
2679 | In Java, it's also common to initialize a fresh instance by calling a set of mutators:
2680 |
2681 | ```java
2682 | java.util.HashMap props = new java.util.HashMap(); /* java */
2683 | props.put("HOME", "/home/myself");
2684 | props.put("SRC", "src");
2685 | props.put("BIN", "classes");
2686 | ```
2687 |
2688 | That's obviously overly verbose, but it can be streamlined using the `doto` macro:
2689 |
2690 | ```clj
2691 | (doto (java.util.HashMap.) ;do to HashMap all these things
2692 | (.put "HOME" "/home/myself")
2693 | (.put "SRC" "src")
2694 | (.put "BIN" "classes"))
2695 | ;=> {"HOME" "/home/myself", "BIN" "classes", "SRC" "src"}
2696 | ```
2697 |
2698 | # Exceptions
2699 |
2700 | Like Java, Clojure also provides `try`, `catch`, `finally` and `throw` forms:
2701 |
2702 | ```clj
2703 | (throw (Exception. "Thrown"))
2704 |
2705 | ;=> Exception Thrown user/eval1201 (form-init8547084957850583270.clj:1)
2706 |
2707 | (defn throw-catch [f]
2708 | [(try
2709 | (f)
2710 | (catch ArithmeticException e "You did not? Not by zero! Noooooooooooo...")
2711 | (catch Exception e (str "You blew it " (.getMessage e)))
2712 | (finally (println "returning... ")))])
2713 | ;=> #'user/throw-catch
2714 |
2715 | (throw-catch #(/ 10 5))
2716 | ;=> returning...
2717 | ;=> [2]
2718 |
2719 | (throw-catch #(/ 10 0))
2720 | ;=> returning...
2721 | ;=> ["You did not? Not by zero! Noooooooooooo..."]
2722 |
2723 | (throw-catch #(throw (Exception. "dawg!")))
2724 | ;=> returning...
2725 | ;=> ["You blew it dawg!"]
2726 | ```
2727 |
2728 | > Clojure doesn't adhere to checked exception requirements, like Java does.
2729 |
2730 | > When an exception is thrown in REPL, the result is stored in a Var named `*e`, which allows you to get more detail about the expression, such as the stack trace:
2731 |
2732 | ```clj
2733 | (.printStackTrace *e)
2734 | ```
2735 |
2736 | # Namespaces
2737 |
2738 | Provide a way to bundle related functions, macros and values.
2739 |
2740 | **Creating namespaces using `ns` macro**
2741 |
2742 | ```clj
2743 | (ns mbo.core.strings)
2744 | ;=> nil
2745 | ;=> mbo.core.strings=> ;from now on, this is our REPL prompt
2746 | ```
2747 |
2748 | There's also a _Var_ `*ns*`, which holds the value of the current namespace.
2749 | We know from before that any _Var_ created will be a member of the current namespace.
2750 |
2751 | ```clj
2752 | mbo.core.strings=> (defn report-ns [] (str "The current namespace is " *ns*))
2753 | ;=> #'mbo.core.strings/report-ns
2754 |
2755 | mbo.core.strings=> (report-ns)
2756 | ;=> "The current namespace is mbo.core.strings"
2757 |
2758 | mbo.core.strings=> (defn sing [] (println "Marjane Marjane, Marjane Marjane, ..."))
2759 | ;=> #'mbo.core.strings/sing
2760 |
2761 | mbo.core.strings=> sing ;Clojure looks it up in the current namespace
2762 | ;=> #
2763 |
2764 | mbo.core.strings=> (ns mbo.core.compat) ;create another namespace
2765 | ;=> nil
2766 |
2767 | mbo.core.compat=> (report-ns) ;try invoking function from another ns
2768 |
2769 | mbo.core.compat=> CompilerException java.lang.RuntimeException:
2770 | ;=> Unable to resolve symbol: report-ns in this context,
2771 | ;=> compiling:(/tmp/form-init8547084957850583270.clj:1:1)
2772 |
2773 | mbo.core.compat=> (mbo.core.strings/report-ns) ;fully qualified name works as expected
2774 | ;=> "The current namespace is mbo.core.compat"
2775 | ```
2776 |
2777 | > referring to a namespace symbol using fully qualified name will only work for namespaces created locally or those previously loaded. Read on, it'll become clear...
2778 |
2779 | **Using `:require` directive to load other namespaces**
2780 |
2781 | ```clj
2782 | mbo.core.compat=> (ns mbo.core.set
2783 | (:require clojure.set))
2784 | ;=> nil
2785 | ;=> mbo.core.set=> ;changed to new ns
2786 |
2787 | mbo.core.set=> (clojure.set/intersection #{1 2 3} #{2 3 4})
2788 | ;=> #{2 3}
2789 |
2790 | mbo.core.set=> (intersection #{1 2 3} #{2 3 4}) ;invoke a clojure.set function directly
2791 |
2792 | ;=> CompilerException java.lang.RuntimeException: Unable to resolve symbol:
2793 | ;=> intersection in this context, compiling:(/tmp/form-init8547084957850583270.clj:1:1)
2794 | ```
2795 |
2796 | This construct indicates that we want the `clojure.set` namespace loaded, but we don't want the mappings of that namespace's symbols to `mbo.core.set` functions.
2797 |
2798 | We can also use `:as` directive to create an additional alias to `clojure.set`:
2799 |
2800 | ```clj
2801 | mbo.core.set=> (ns mbo.core.set-alias
2802 | #_=> (:require [clojure.set :as s]))
2803 | ;=> nil
2804 |
2805 | mbo.core.set-alias=> (s/intersection #{1 2 3} #{2 3 4})
2806 | ;=> #{2 3}
2807 | ```
2808 |
2809 | The qualified namespace form (e.g. `clojure.set`) looks the same as a call to a _static class method_. The difference is that a _namespace symbol_ can only be used as a qualifier, whereas a _class symbol_ can also be referenced independently:
2810 |
2811 | ```clj
2812 | mbo.core.set-alias=> clojure.set
2813 |
2814 | ;=> mbo.core.set-alias=> CompilerException java.lang.ClassNotFoundException:
2815 | ;=> clojure.set, compiling:(/tmp/form-init8547084957850583270.clj:1:691)
2816 |
2817 | mbo.core.set-alias=> java.lang.Object
2818 | ;=> java.lang.Object
2819 | ```
2820 |
2821 | > That vagaries of namespace mappings from symbols to _Vars_, both qualified and unqualified, have the potential for confusion between _class names_ and _static methods_. In the beginning, that is. The differences will begin to feel natural as we progress (at least that's what _The joy of Clojure_ book promises :)
2822 | > One of the Clojure idioms is to use `my.Class` and `my.ns` for naming classes and namespaces, to help eliminate potential confusion.
2823 |
2824 | **Loading and creating mappings with `:use`**
2825 |
2826 | `:use`, unlike `:require`, maps Vars in another namespace to names in your own. That is typically used to avoid calling each function or macro with the qualifying namespace symbol:
2827 |
2828 | ```clj
2829 | mbo.core.set-alias=> (ns mbo.test
2830 | #_=> (:use [clojure.string :only [capitalize]]))
2831 | ;=> nil
2832 |
2833 | mbo.test=> (map capitalize ["one" "two"])
2834 | ;=> ("One" "Two")
2835 | ;=> mbo.test=>
2836 | ```
2837 |
2838 | `:only` is used to indicate that only the listed functions should be mapped in the new namespace (good practice). The `:exclude` directive does the opposite.
2839 | `:use`, besides creating mappings, implicitly invokes `:require`.
2840 |
2841 | > the idiomatic strategy for avoiding conflicts is to use `:require` with `:as` to create a namespace alias
2842 |
2843 | **Create mappings with `:refer`**
2844 |
2845 | `:refer` is a directive that works almost exactly like `:use`, except that it only creates mappings for libraries that have already been loaded (by being previously defined, by being one of Clojure's core namespaces or by having been explicitly loaded using `:require`).
2846 |
2847 | **Loading Java classes with `:import`**
2848 |
2849 | ```clj
2850 | mbo.test=> (ns mbo.java
2851 | #_=> (:import [java.util HashMap]
2852 | #_=> [java.util.concurrent.atomic.AtomicLong]))
2853 | ;=> nil
2854 |
2855 | mbo.java=> (HashMap. {"happy?" true})
2856 | ;=> {"happy?" true}
2857 | ```
2858 |
2859 | > Any classes in the `java.lang` package are implicitly imported when namespaces are created
2860 |
2861 | **`nil` punning**
2862 |
2863 | Since, in Clojure, everything except `nil` and `false` is `true`, empty collections evaluate to `true` in boolean context. We need a way to test whether a collection is empty or not.
2864 |
2865 | This is where _nil punning_ comes in:
2866 |
2867 | ```clj
2868 | (seq [1 2 3])
2869 | ;=> (1 2 3)
2870 |
2871 | (seq [])
2872 | ;=> nil
2873 | ```
2874 |
2875 | `seq` function returns a sequence view of a collection or `nil` if the collection is empty.
2876 |
2877 | ```clj
2878 | (defn print-seq [s]
2879 | (when (seq s)
2880 | (prn (first s)) ;prn prints each object in a newline (to the output stream)
2881 | (recur (rest s))))
2882 |
2883 | (print-seq [1 2])
2884 | ;=> 1
2885 | ;=> 2
2886 | ;=> nil
2887 | ```
2888 |
2889 | The use of `seq` as a terminating condition is the idiomatic way of testing whether a sequence is empty
2890 |
2891 | # Destructuring
2892 |
2893 | Allows you to place a collection of names in a binding form where normally you'd put just a single name.
2894 |
2895 | > Destructuring is loosely related to _pattern matching_ (found in Haskell or [Scala](https://github.com/mbonaci/scala#case-classes-and-pattern-matching)), but much more limited in scope. For full-featured pattern matching in Clojure use [matchure](http://github.com/dcolthorp/matchure).
2896 |
2897 | Perhaps the simplest form of destructuring is picking apart a sequential thing (e.g. a vector or a list), giving each item a name:
2898 |
2899 | ```clj
2900 | (let [[fname mname lname] ["Frane" "Luka" "Bonaci"]]
2901 | (str lname ", " fname " " mname))
2902 | ;=> "Bonaci, Frane Luka"
2903 |
2904 | ;; although this is syntactically correct, it isn't factually accurate
2905 | ;; my month and a half old twins are named Frane and Luka :)
2906 | ;; what can I say, my wife is a hero (that's what everybody's telling me these days)
2907 | ;; hmmm, I wonder why?
2908 | ```
2909 |
2910 | This was a so called _positional destructuring_, which, as you might expect, doesn't work on maps and sets, because they are not logically aligned sequentially. But it does work on `java.util.regex.Matcher` and anything implementing `CharSequence` and `java.util.RandomAccess` interfaces.
2911 |
2912 | **Destructuring with a vector**
2913 |
2914 | We can also use an ampersand in a destructuring vector to indicate that any remaining values of the input should be collected into a (possibly lazy) `seq`:
2915 |
2916 | ```clj
2917 | (let [[a b c & more] (range 10)]
2918 | (println "a b c are: " a b c)
2919 | (println "the rest is: " more))
2920 | ;=> a b c are: 0 1 2
2921 | ;=> the rest is: (3 4 5 6 7 8 9)
2922 | ```
2923 |
2924 | A useful feature of vector destructuring is `:as`, which is used to bind a local to the entire collection. It must be placed at the end, even after the `&` local (if it exists):
2925 |
2926 | ```clj
2927 | (let [range-vec (vec (range 10))
2928 | [a b c & more :as all] range-vec]
2929 | (println "a b c are: " a b c)
2930 | (println "the rest is " more)
2931 | (println "all is: " all))
2932 | ;=> a b c are: 0 1 2
2933 | ;=> the rest is (3 4 5 6 7 8 9)
2934 | ;=> all is: [0 1 2 3 4 5 6 7 8 9]
2935 | ```
2936 |
2937 | > Notice the difference between `&` and `:as`. While `:all` produces a vector, `&` results with a `seq`.
2938 |
2939 | **Destructuring with a map**
2940 |
2941 | ```clj
2942 | (def full-name-map
2943 | {:fname "Frane" :mname "Luka" :lname "Bonaci"})
2944 |
2945 | (let [{fname :fname, mname :mname, lname :lname} full-name-map]
2946 | (str lname ", " fname " " mname))
2947 | ;=> "Bonaci, Frane Luka"
2948 | ```
2949 |
2950 | Here, the `:keys` feature might come in handy:
2951 |
2952 | ```clj
2953 | (let [{:keys [fname mname lname]} full-name-map]
2954 | (str lname ", " fname " " mname))
2955 | ;=> "Bonaci, Frane Luka"
2956 | ```
2957 |
2958 | By using `:keys`, we're telling Clojure that the next form will be a vector of names that it should convert to keywords (e.g. `:fname`), in order to look
2959 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbonaci/clojure/6bd38e54e9f714183aa039b965d7c03ffdfce220/index.html
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "clojure",
3 | "version": "0.0.5",
4 | "description": "(Now former) Java programmer sneaks up on Clojure",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "https://github.com/mbonaci/clojure.git"
12 | },
13 | "keywords": [
14 | "clojure"
15 | ],
16 | "author": "mbonaci",
17 | "license": "MIT",
18 | "bugs": {
19 | "url": "https://github.com/mbonaci/clojure/issues"
20 | },
21 | "homepage": "https://mbonaci.github.io/clojure",
22 | "devDependencies": {
23 | "grunt": "~0.4.2",
24 | "assemble": "~0.4.35",
25 | "grunt-newer": "~0.6.1",
26 | "assemble-contrib-markdown": "~0.1.0"
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/resources/BalancedBinaryTree.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbonaci/clojure/6bd38e54e9f714183aa039b965d7c03ffdfce220/resources/BalancedBinaryTree.png
--------------------------------------------------------------------------------
/resources/ClojureEvaluation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbonaci/clojure/6bd38e54e9f714183aa039b965d7c03ffdfce220/resources/ClojureEvaluation.png
--------------------------------------------------------------------------------
/resources/TraditionalEvaluation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbonaci/clojure/6bd38e54e9f714183aa039b965d7c03ffdfce220/resources/TraditionalEvaluation.png
--------------------------------------------------------------------------------
/resources/UnbalancedBinaryTree-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbonaci/clojure/6bd38e54e9f714183aa039b965d7c03ffdfce220/resources/UnbalancedBinaryTree-01.png
--------------------------------------------------------------------------------
/resources/UnbalancedBinaryTree-02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbonaci/clojure/6bd38e54e9f714183aa039b965d7c03ffdfce220/resources/UnbalancedBinaryTree-02.png
--------------------------------------------------------------------------------
/resources/UnbalancedBinaryTree-03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbonaci/clojure/6bd38e54e9f714183aa039b965d7c03ffdfce220/resources/UnbalancedBinaryTree-03.png
--------------------------------------------------------------------------------
/resources/UnbalancedBinaryTree-04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbonaci/clojure/6bd38e54e9f714183aa039b965d7c03ffdfce220/resources/UnbalancedBinaryTree-04.png
--------------------------------------------------------------------------------
/resources/UnbalancedBinaryTree.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbonaci/clojure/6bd38e54e9f714183aa039b965d7c03ffdfce220/resources/UnbalancedBinaryTree.png
--------------------------------------------------------------------------------
/resources/ast.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbonaci/clojure/6bd38e54e9f714183aa039b965d7c03ffdfce220/resources/ast.png
--------------------------------------------------------------------------------
/resources/lein.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbonaci/clojure/6bd38e54e9f714183aa039b965d7c03ffdfce220/resources/lein.gif
--------------------------------------------------------------------------------
/resources/lein.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbonaci/clojure/6bd38e54e9f714183aa039b965d7c03ffdfce220/resources/lein.jpg
--------------------------------------------------------------------------------
/resources/lein.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbonaci/clojure/6bd38e54e9f714183aa039b965d7c03ffdfce220/resources/lein.png
--------------------------------------------------------------------------------
/resources/light-table-unbalanced-tree-example.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbonaci/clojure/6bd38e54e9f714183aa039b965d7c03ffdfce220/resources/light-table-unbalanced-tree-example.PNG
--------------------------------------------------------------------------------
/resources/repl.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbonaci/clojure/6bd38e54e9f714183aa039b965d7c03ffdfce220/resources/repl.png
--------------------------------------------------------------------------------
/resources/vector-lookup-options.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbonaci/clojure/6bd38e54e9f714183aa039b965d7c03ffdfce220/resources/vector-lookup-options.png
--------------------------------------------------------------------------------
/src/lighttable.tryout.clj:
--------------------------------------------------------------------------------
1 | ;; Anything you type in here will be executed
2 | ;; immediately with the results shown on the
3 | ;; right.
4 |
5 | (take 9 (cycle [1 2 3 4]))
6 |
7 | (reverse "woolf")
8 | (apply str (reverse "woolf"))
9 | (str (reverse "woolf"))
10 |
11 | (doto (new javax.swing.JFrame) (.add (javax.swing.JLabel. "Hello")) .pack .show)
12 |
13 | (type javax.swing.JFrame)
14 |
--------------------------------------------------------------------------------
/src/mbo-unbalanced-binary-tree.clj:
--------------------------------------------------------------------------------
1 | (ns mbo-unbalanced-binary-tree)
2 |
3 | (defn xseq [t]
4 | (when t
5 | (concat (xseq (:L t)) [(:val t)] (xseq (:R t)))))
6 |
7 | (defn xconj [t v]
8 | (cond
9 | (nil? t) {:val v, :L nil, :R nil}
10 | (< v (:val t))
11 | {:val (:val t),
12 | :L (xconj (:L t) v),
13 | :R (:R t)}
14 | :else {:val (:val t)
15 | :L (:L t)
16 | :R (xconj (:R t) v)}
17 | ))
18 |
19 | (def f1 (xconj nil 50))
20 |
21 | (def f2 (xconj f1 40))
22 |
23 | (def f3 (xconj f2 60))
24 |
25 | (def f4 (xconj f3 10))
26 |
27 | (def f5 (xconj f4 30))
28 |
29 | (def f6 (xconj f5 20))
30 |
31 | (def f7 (xconj f6 35))
32 |
33 |
34 | (xseq f7)
35 |
--------------------------------------------------------------------------------
/src/repl.clj:
--------------------------------------------------------------------------------
1 | (defn xors [max-x max-y]
2 | (for [x (range max-x) y (range max-y)] [x y (bit-xor x y)])
3 |
4 | (xors 2 2)
--------------------------------------------------------------------------------
/src/scratch/.gitignore:
--------------------------------------------------------------------------------
1 | /target
2 | /lib
3 | /classes
4 | /checkouts
5 | pom.xml
6 | pom.xml.asc
7 | *.jar
8 | *.class
9 | .lein-deps-sum
10 | .lein-failures
11 | .lein-plugins
12 | .lein-repl-history
13 |
--------------------------------------------------------------------------------
/src/scratch/README.md:
--------------------------------------------------------------------------------
1 | # scratch
2 |
3 | A Clojure library designed to ... well, that part is up to you.
4 |
5 | ## Usage
6 |
7 | FIXME
8 |
9 | ## License
10 |
11 | Copyright © 2014 FIXME
12 |
13 | Distributed under the Eclipse Public License, the same as Clojure.
14 |
--------------------------------------------------------------------------------
/src/scratch/doc/intro.md:
--------------------------------------------------------------------------------
1 | # Introduction to scratch
2 |
3 | TODO: write [great documentation](http://jacobian.org/writing/great-documentation/what-to-write/)
4 |
--------------------------------------------------------------------------------
/src/scratch/project.clj:
--------------------------------------------------------------------------------
1 | (defproject scratch "0.1.0-SNAPSHOT"
2 | :description "FIXME: write description"
3 | :url "http://example.com/FIXME"
4 | :license {:name "Eclipse Public License"
5 | :url "http://www.eclipse.org/legal/epl-v10.html"}
6 | :dependencies [[org.clojure/clojure "1.5.1"]])
7 |
--------------------------------------------------------------------------------
/src/scratch/src/scratch/core.clj:
--------------------------------------------------------------------------------
1 | (ns scratch.core)
2 |
3 | (defn foo
4 | "I don't do a whole lot."
5 | [x]
6 | (println x "Hello, World!"))
7 |
--------------------------------------------------------------------------------
/src/scratch/test/scratch/core_test.clj:
--------------------------------------------------------------------------------
1 | (ns scratch.core-test
2 | (:require [clojure.test :refer :all]
3 | [scratch.core :refer :all]))
4 |
5 | (deftest a-test
6 | (testing "FIXME, I fail."
7 | (is (= 0 1))))
8 |
--------------------------------------------------------------------------------
/src/xors.clj:
--------------------------------------------------------------------------------
1 | (defn xors [xs ys]
2 | (for [x (range xs) y (range ys)]
3 | [x y (rem (bit-xor x y) 256)]))
4 |
5 |
6 | (defn f-values [f xs ys]
7 | (for [x (range xs) y (range ys)]
8 | [x y (rem (f x y) 256)]))
9 |
10 |
11 | (defn clear [g] (.clearRect g 0 0 200 200))
12 |
13 |
14 | (defn draw-values [f xs ys]
15 | (clear gfx)
16 | (.setSize frame (java.awt.Dimension. xs ys))
17 | (doseq [[x y v] (f-values f xs ys)]
18 | (.setColor gfx (java.awt.Color. v v v))
19 | (.fillRect gfx x y 1 1)))
20 |
21 |
22 | (for [method (seq (.getMethods java.awt.Frame))
23 | :let [method-name (.getName method)]
24 | :when (re-find #"." method-name)]
25 | method-name)
--------------------------------------------------------------------------------