├── .gitignore
├── README.md
├── SECURITY.md
├── images
├── clojure-evaluation.png
├── collections-seq-lazy-GC-safe.svg
├── collections-seq-lazy-GC-unsafe.svg
├── collections-seq-lazy-first.svg
├── collections-seq-lazy-initial.svg
├── collections-seq-lazy-rest.svg
├── collections-seq-lazy-second.svg
├── collections-seq-lazy-third.svg
├── collections-seq-list-first.svg
├── collections-seq-list-initial.svg
├── collections-seq-list-rest.svg
├── collections-seq-list-second.svg
├── collections-seq-vector-first.svg
├── collections-seq-vector-initial.svg
├── collections-seq-vector-rest.svg
├── collections-seq-vector-second.svg
├── collections-seq-vector-seq.svg
├── namespaces-total.svg
├── state1.png
├── state2.png
├── state3.png
├── state4.png
├── state5.png
├── structure-and-semantics.png
└── traditional-evaluation.png
├── project.clj
└── src
├── cljlab
├── flowcontrol.clj
├── functions.clj
├── namespaces.clj
├── ordered-collections.clj
├── polymorphism.clj
├── sequences.clj
├── start.clj
├── state.clj
├── syntax.clj
└── unordered-collections.clj
└── start.clj
/.gitignore:
--------------------------------------------------------------------------------
1 | /target
2 | /classes
3 | /checkouts
4 | pom.xml
5 | pom.xml.asc
6 | .gorilla-port
7 | *.jar
8 | *.class
9 | /.lein-*
10 | /.nrepl-port
11 | .bundle
12 | /_site
13 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Welcome to Clojure!
2 |
3 | This repository is designed to be a set of interactive learning materials introducing Clojure.
4 | The materials are suitable for use either individually or in group settings. The content is
5 | delivered using [Gorilla REPL](http://gorilla-repl.org/), which combines text information with
6 | embedded REPLs (interactive Clojure code editors).
7 |
8 | The content in this course was developed by Cognitect for Clojure training events held at both
9 | conferences and corporate settings. This particular version of the materials was first used in
10 | the Clojure/West 2015 Intro to Clojure 2-day course.
11 |
12 | Table of contents:
13 |
14 | - Syntax
15 | - Functions
16 | - Ordered collections
17 | - Unordered collections
18 | - Flow control
19 | - Namespaces
20 | - Sequences
21 | - Polymorphism
22 | - State
23 |
24 | ## Run from repository
25 |
26 | This is the normal way to interact with these materials.
27 |
28 | ### Prerequisites
29 |
30 | - Install a [Java Development Kit](http://www.oracle.com/technetwork/java/javase/downloads/index.html) (1.6 or later)
31 | - Install the [leiningen build tool](http://leiningen.org/)
32 |
33 | 1) Clone this repo
34 |
35 | ```
36 | git clone git@github.com:cognitect/clojure-lab.git
37 | cd clojure-lab
38 | ```
39 |
40 | 2) Start the gorilla repl server
41 |
42 | ```
43 | lein gorilla :port 55555
44 | ```
45 |
46 | 3) Open the lab page in your web browser
47 |
48 | [Start](http://127.0.0.1:55555/worksheet.html?filename=src/cljlab/start.clj)
49 |
50 | ## Creating a standalone package
51 |
52 | If you are teaching a course this may be useful to create a standalone package for distribution to
53 | students.
54 |
55 | 1) Create the uberjar:
56 |
57 | ```
58 | rm target
59 | lein uberjar
60 | ```
61 |
62 | 2) Compress the directory into a zip (this may vary per platform):
63 |
64 | ```
65 | cd ..
66 | zip -r clojure-lab clojure-lab/images clojure-lab/src clojure-lab/target/*-standalone.jar
67 | ```
68 |
69 | ## Running the standalone package
70 |
71 | If you are taking a course with a standalone package, this method can be used to
72 | run the materials.
73 |
74 | 1) Unzip the zip file
75 |
76 | ```
77 | unzip clojure-lab.zip
78 | cd clojure-lab
79 | ```
80 |
81 | 2) Start the server
82 |
83 | ```
84 | java -jar target/clojure-lab-0.1.0-SNAPSHOT-standalone.jar
85 | ```
86 |
87 | 3) View the page in your browser
88 |
89 | [Start](http://127.0.0.1:55555/worksheet.html?filename=src/cljlab/start.clj)
90 |
91 | ## Contributions
92 |
93 | This repository is free for all to use in learning Clojure. You are welcome to use it for any non-commercial use - free public workshops, internal company workshops, etc.
94 |
95 | Contributions to this repository are welcome via pull request! However, we would like to retain copyright by Cognitect for these materials. Thus, we request that you complete the following online agreement to assign copyright to Cognitect before any contribution can be accepted:
96 |
97 | [Cognitect Contributor Agreement](https://secure.echosign.com/public/hostedForm?formid=8JU33Z7A7JX84U)
98 |
99 | If you have any questions, please contact alex.miller@cognitect.com.
100 |
101 | ## Copyright
102 |
103 | Copyright © 2015 Cognitect
104 |
105 | 
Clojure Lab by Cognitect is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
106 |
107 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 | # Security Policy for Nubank Open Source Projects
2 |
3 | ## Supported Versions
4 |
5 | Nubank supports the latest version of each of our open-source projects. Once a new version is released, we stop providing patches for security issues in older versions.
6 |
7 | ## Reporting Security Issues
8 |
9 | Your efforts to responsibly disclose your findings are sincerely appreciated and will be taken into account to acknowledge your contributions.
10 | If you discover a vulnerability, please do the following:
11 |
12 | 1. E-mail your findings to [security@nubank.com.br](mailto:security@nubank.com.br). If the issue is sensitive, please use [our PGP key](https://nubank.com.br/.well-known/security.txt) to encrypt your communications with us.
13 | 2. Do not take advantage of the vulnerability or problem you have discovered.
14 | 3. Do not reveal the problem to others until it has been resolved.
15 | 4. Provide sufficient information to reproduce the problem so we can resolve it as quickly as possible.
16 | 5. You will receive a response from us acknowledging receipt of your vulnerability report.
17 | 6. You'll receive regular updates about our progress.
18 | 7. Once the issue is resolved, we would like to mention your name in any dispatches about the issue so that we can credit you for your discovery. Please engage in responsible privacy practices when disclosing bugs to us, and we'll handle each report with utmost urgency.
19 |
20 | ## Preferred Languages
21 |
22 | We prefer all communications to be in English.
23 |
24 | ## Policy Adherence
25 |
26 | We greatly value your assistance in discovering and reporting vulnerabilities, and look forward to working with users who wish to help ensure Nubank's open-source projects' safety and security. Thank you for supporting Nubank's mission and helping ensure the highest levels of security for our community!
27 |
--------------------------------------------------------------------------------
/images/clojure-evaluation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cognitect/clojure-lab/af560ee7181ef3462b46af5f227e0c2048da9d90/images/clojure-evaluation.png
--------------------------------------------------------------------------------
/images/collections-seq-lazy-first.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
383 |
--------------------------------------------------------------------------------
/images/collections-seq-lazy-initial.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
355 |
--------------------------------------------------------------------------------
/images/collections-seq-lazy-rest.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
410 |
--------------------------------------------------------------------------------
/images/collections-seq-lazy-second.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
421 |
--------------------------------------------------------------------------------
/images/collections-seq-list-initial.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
414 |
--------------------------------------------------------------------------------
/images/collections-seq-list-rest.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
442 |
--------------------------------------------------------------------------------
/images/collections-seq-vector-first.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
412 |
--------------------------------------------------------------------------------
/images/collections-seq-vector-initial.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
368 |
--------------------------------------------------------------------------------
/images/collections-seq-vector-seq.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
429 |
--------------------------------------------------------------------------------
/images/state1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cognitect/clojure-lab/af560ee7181ef3462b46af5f227e0c2048da9d90/images/state1.png
--------------------------------------------------------------------------------
/images/state2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cognitect/clojure-lab/af560ee7181ef3462b46af5f227e0c2048da9d90/images/state2.png
--------------------------------------------------------------------------------
/images/state3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cognitect/clojure-lab/af560ee7181ef3462b46af5f227e0c2048da9d90/images/state3.png
--------------------------------------------------------------------------------
/images/state4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cognitect/clojure-lab/af560ee7181ef3462b46af5f227e0c2048da9d90/images/state4.png
--------------------------------------------------------------------------------
/images/state5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cognitect/clojure-lab/af560ee7181ef3462b46af5f227e0c2048da9d90/images/state5.png
--------------------------------------------------------------------------------
/images/structure-and-semantics.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cognitect/clojure-lab/af560ee7181ef3462b46af5f227e0c2048da9d90/images/structure-and-semantics.png
--------------------------------------------------------------------------------
/images/traditional-evaluation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cognitect/clojure-lab/af560ee7181ef3462b46af5f227e0c2048da9d90/images/traditional-evaluation.png
--------------------------------------------------------------------------------
/project.clj:
--------------------------------------------------------------------------------
1 | (defproject clojure-lab "0.1.0-SNAPSHOT"
2 | :description "Interactive materials for learning Clojure"
3 | :url "https://github.com/cognitect/clojure-lab"
4 | :plugins [[lein-gorilla "0.3.6"]]
5 | :dependencies [[org.clojure/clojure "1.8.0"]
6 | [gorilla-repl "0.3.6"]]
7 | :aot [start]
8 | :main start)
9 |
--------------------------------------------------------------------------------
/src/cljlab/namespaces.clj:
--------------------------------------------------------------------------------
1 | ;; gorilla-repl.fileformat = 1
2 |
3 | ;; **
4 | ;;; # Clojure Namespaces
5 | ;;;
6 | ;;;
7 | ;; **
8 |
9 | ;; **
10 | ;;; ## What is a namespace?
11 | ;;; * Conceptual version
12 | ;;; * A way to disambiguate names
13 | ;;; * Concrete version
14 | ;;; * Mappings from _symbols_ to
15 | ;;; * Vars
16 | ;;; * Java classes
17 | ;;; * Aliases to other namespaces
18 | ;; **
19 |
20 | ;; **
21 | ;;; ## What is a var?
22 | ;;; * An association between a _symbol_ and a _value_
23 | ;;; * `def`
24 | ;;; * Creates a new var in the current namespace
25 | ;;; * Optionally creates _root binding_ to a value
26 | ;;; * `defn`
27 | ;;; * Shortcut for `def` + `fn`
28 | ;;; * Creates a new var whose value is a function
29 | ;; **
30 |
31 | ;; **
32 | ;;; ## What is a symbol?
33 | ;;; * Just a label
34 | ;;; * A name _string_
35 | ;;; * With an optional namespace _string_
36 | ;;; * Has no value
37 | ;;;
38 | ;;; ```clojure
39 | ;;; foo ; Unqualified symbol
40 | ;;; bar/foo ; Namespace-qualified symbol
41 | ;;; ```
42 | ;; **
43 |
44 | ;; **
45 | ;;; ## Creating namespaces
46 | ;;; ### `ns`
47 | ;;; * At the top of every source file
48 | ;;; * Creates a namespace
49 | ;;; * Automatically refers all of `clojure.core`
50 | ;;;
51 | ;;; ```clojure
52 | ;;; (ns com.some-example.my-app)
53 | ;;; ```
54 | ;; **
55 |
56 | ;; **
57 | ;;; ### Names into files
58 | ;;; * Dots become directory separators
59 | ;;; * Hyphens become underscores
60 | ;;; * Add `.clj` to the end
61 | ;;; * Find on the CLASSPATH
62 | ;;;
63 | ;;; ```clojure
64 | ;;; ;; in file $CLASSPATH/com/some_example/my_app.clj
65 | ;;; (ns com.some-example.my-app)
66 | ;;; ```
67 | ;; **
68 |
69 | ;; **
70 | ;;; ### The JVM classpath
71 | ;;; * Where to find code to load
72 | ;;; * List of directories and JAR files
73 | ;;; * Specified when launching the JVM
74 | ;;; * Cannot be changed (normally)
75 | ;;; * Managed by tools such as Leiningen
76 | ;;;
77 | ;;; ```clojure
78 | ;;; ;; Show the classpath
79 | ;;; (System/getProperty "java.class.path")
80 | ;;; ```
81 | ;; **
82 |
83 | ;; **
84 | ;;; ## Namespace operations
85 | ;;; * Load (_require_)
86 | ;;; * Copy (_refer_) symbol -> var mappings
87 | ;;; * Make a shortcut (_alias_)
88 | ;; **
89 |
90 | ;; **
91 | ;;; ### `ns :require`
92 | ;;; * Loads a namespace
93 | ;;; * Optionally
94 | ;;; * Provides an alias
95 | ;;; * Refers some symbols
96 | ;;; * Never loads the same code twice
97 | ;; **
98 |
99 | ;; **
100 | ;;; ### `ns :require` example
101 | ;;; ```clojure
102 | ;;; (ns com.some-example.my-app
103 | ;;; (:require clojure.string
104 | ;;; [clojure.set :as set]
105 | ;;; [clojure.java.io :refer (file reader)]))
106 | ;;; ```
107 | ;; **
108 |
109 | ;; **
110 | ;;; ### `ns :require` bare
111 | ;;; ```clojure
112 | ;;; (ns ... (:require clojure.string ...))
113 | ;;; ```
114 | ;;;
115 | ;;; * Element inside `(:require ...)` is a symbol
116 | ;;; * Just load the code
117 | ;;; * Vars available as fully-qualified symbols
118 | ;;; * e.g. `clojure.string/replace`
119 | ;; **
120 |
121 | ;; **
122 | ;;; ### `ns :require :as`
123 | ;;; ```clojure
124 | ;;; (ns ... (:require [clojure.set :as set] ...))
125 | ;;; ```
126 | ;;;
127 | ;;; * Element inside `(:require ...)` is a vector
128 | ;;; * Like `[_name_ :as _alias_]`
129 | ;;; * Load code and create an alias
130 | ;;; * Vars available under shorter alias
131 | ;;; * e.g. `set/union`
132 | ;; **
133 |
134 | ;; **
135 | ;;; ### `ns :require :refer`
136 | ;;; ```clojure
137 | ;;; (ns ... (:require [clojure.java.io :refer (file reader)] ...))
138 | ;;; ```
139 | ;;;
140 | ;;; * Element inside `(:require ...)` is a vector
141 | ;;; * Like `[_name_ :refer (_symbols_+)]`
142 | ;;; * Load code and copy symbol -> var bindings
143 | ;;; * Vars available without namespace qualification
144 | ;;; * e.g. `reader`
145 | ;; **
146 |
147 | ;; **
148 | ;;; ### `ns :use :only`
149 | ;;; ```clojure
150 | ;;; (ns ... (:use [clojure.java.io :only (file reader)] ...))
151 | ;;; ```
152 | ;;;
153 | ;;; * Older (pre-1.4) form of `:require :refer`
154 | ;;; * `(:use ...)` instead of `(:require ...)`
155 | ;;; * Element inside `(:use ...)` is a vector
156 | ;;; * Like `[_name_ :only (_symbols_+)]`
157 | ;;; * Vars available without namespace qualification
158 | ;;; * e.g. `reader`
159 | ;; **
160 |
161 | ;; **
162 | ;;; ### `ns :import`
163 | ;;; ```clojure
164 | ;;; (ns com.some-example.my-app
165 | ;;; (:import java.io.File
166 | ;;; (java.util Map List Map$Entry)))
167 | ;;; ```
168 | ;;;
169 | ;;; * Element inside `(:import ...)` is
170 | ;;; * A package-qualified class name
171 | ;;; * Or a list like `(_package_ _classes_+)`
172 | ;;; * Java "inner classes" are named `Outer$Inner`
173 | ;;; * Every namespace automatically imports `java.lang`
174 | ;; **
175 |
176 | ;; **
177 | ;;; ## Namespaces at the REPL
178 | ;;; ### Where am I?
179 | ;;; * `*ns*` is the current namespace
180 | ;;; * `in-ns` switches namespaces
181 | ;;; * Takes a _symbol_ (quoted)
182 | ;;; * Creates namespace if it doesn't exist
183 | ;;; * Does _not_ automatically refer `clojure.core` like `ns`
184 | ;; **
185 |
186 | ;; **
187 | ;;; ### `in-ns`
188 | ;; **
189 |
190 | ;; @@
191 | (ns cljlab.namespaces)
192 | ;; @@
193 |
194 | ;; @@
195 | (in-ns 'never-before-seen)
196 | ;; @@
197 |
198 | ;; @@
199 | (println "This won't work")
200 | ;; @@
201 |
202 | ;; @@
203 | (clojure.core/println "This will")
204 | ;; @@
205 |
206 | ;; @@
207 | ;; Get back to the namespace for this worksheet
208 | (in-ns 'cljlab.namespaces)
209 | ;; @@
210 |
211 | ;; **
212 | ;;; ### `require`
213 | ;;; * `require` is also a function
214 | ;;; * Same syntax as in `(ns ... (:require ...))`
215 | ;;; * But `require` is not a keyword
216 | ;;; * Arguments must be _quoted_ to prevent evaluation
217 | ;; **
218 |
219 | ;; @@
220 | (require clojure.set)
221 | ;; @@
222 |
223 | ;; @@
224 | (require '[clojure.set :as set])
225 | ;; @@
226 |
227 | ;; @@
228 | (set/union #{1 3} #{2 4})
229 | ;; @@
230 |
231 | ;; **
232 | ;;; ### `require :reload`
233 | ;;; * `require` never loads the same file twice
234 | ;;; * To get new definitions, add `:reload` flag
235 | ;;; * `:reload-all` will recursively reload dependencies
236 | ;;;
237 | ;;; ```clojure
238 | ;;; (require 'com.example :reload)
239 | ;;; (require 'com.example.myapp :reload-all)
240 | ;;; ```
241 | ;; **
242 |
243 | ;; **
244 | ;;; ### `import`
245 | ;;; * `import` is also a macro
246 | ;;; * Same syntax as in `(ns ... (:import ...))`
247 | ;;; * But `import` is not a keyword
248 | ;;; * Arguments do _not_ need to be quoted
249 | ;; **
250 |
251 | ;; @@
252 | (import (java.util Random))
253 | ;; @@
254 |
255 | ;; @@
256 | (.nextInt (Random.))
257 | ;; @@
258 |
259 | ;; **
260 | ;;; ### Namespace concepts
261 | ;;; Click on the image to view full-size in a new window (in browsers that support SVG).
262 | ;;; 
263 | ;; **
264 |
265 | ;; **
266 | ;;;
267 | ;;; ### File vs. REPL
268 | ;;; ```clojure
269 | ;;; ;; In a source file ;; At the REPL
270 | ;;; ;; --------------------------- ;; ---------------------------
271 | ;;; (ns foo) (in-ns 'foo)
272 | ;;;
273 | ;;; (ns foo (:require bar)) (require 'bar)
274 | ;;; (ns foo (:require [bar :as b])) (require '[bar :as b])
275 | ;;; (ns foo (:import (java.io File))) (import (java.io File))
276 | ;;; ```
277 | ;; **
278 |
279 | ;; **
280 | ;;; ## Examining symbols and namespaces
281 | ;;; ### Examining and creating symbols
282 | ;; **
283 |
284 | ;; @@
285 | (name 'com.example/foo)
286 | ;; @@
287 |
288 | ;; @@
289 | (namespace 'com.example/foo)
290 | ;; @@
291 |
292 | ;; @@
293 | (namespace 'foo)
294 | ;; @@
295 |
296 | ;; @@
297 | (symbol "foo")
298 | ;; @@
299 |
300 | ;; @@
301 | (symbol "com.example" "foo")
302 | ;; @@
303 |
304 | ;; **
305 | ;;; ### Finding namespaces
306 | ;; **
307 |
308 | ;; @@
309 | ;; Doesn't work:
310 | clojure.set
311 | ;; @@
312 |
313 | ;; @@
314 | (find-ns 'clojure-set)
315 | ;; @@
316 |
317 | ;; **
318 | ;;; ### Viewing namespace mappings
319 | ;;;
320 | ;;;
321 | ;;; Function |
322 | ;;; Returns map of symbols to... |
323 | ;;;
324 | ;;;
325 | ;;; `ns-map` |
326 | ;;; all vars and classes |
327 | ;;;
328 | ;;;
329 | ;;; -> `ns-interns` |
330 | ;;; all vars created in this namespace |
331 | ;;;
332 | ;;;
333 | ;;; -> -> `ns-publics` |
334 | ;;; all *public* vars in this namespace |
335 | ;;;
336 | ;;;
337 | ;;; -> `ns-refers` |
338 | ;;; *referred* vars from other namespaces |
339 | ;;;
340 | ;;;
341 | ;;; -> `ns-imports` |
342 | ;;; Java classes |
343 | ;;;
344 | ;;;
345 | ;;; `ns-aliases` |
346 | ;;; aliased namespaces |
347 | ;;;
348 | ;;;
349 | ;; **
350 |
351 | ;; **
352 | ;;; ### Viewing namespace mappings example
353 | ;; **
354 |
355 | ;; @@
356 | (ns-map 'user)
357 | ;; @@
358 |
359 | ;; @@
360 | (ns-aliases 'user)
361 | ;; @@
362 |
363 | ;; **
364 | ;;; ## Private vars
365 | ;;; * Add `^:private` metadata to def'd symbol
366 | ;;; * `defn-` is shortcut for private fn
367 | ;;; * Prevents accidental refer
368 | ;;; * Prevents accidental use by qualified symbol
369 | ;;; * Not truly hidden, can expose by deref'ing var
370 | ;;;
371 | ;;; ### Private vars example
372 | ;; **
373 |
374 | ;; @@
375 | (def ^:private secret "trustno1")
376 | ;; @@
377 |
378 | ;; @@
379 | (in-ns 'foo.bar)
380 | ;; @@
381 |
382 | ;; @@
383 | (user/secret)
384 | ;; @@
385 |
386 | ;; @@
387 | @#'user/secret
388 | ;; @@
389 |
390 | ;; @@
391 | ;; Return to the namespace for this worksheet
392 | (in-ns 'cljlab.namespaces)
393 | ;; @@
394 |
395 | ;; **
396 | ;;; ## LAB: Namespaces
397 | ;;;
398 | ;;; ### Entering a namespace
399 | ;;; At the REPL, use `in-ns` to enter a new namespace `alpha`.
400 | ;; **
401 |
402 | ;; @@
403 |
404 | ;; @@
405 |
406 | ;; **
407 | ;;; ### An empty namespace
408 | ;;; In the `alpha` namespace, try to call a common function like `println`. Why doesn't it work?
409 | ;; **
410 |
411 | ;; @@
412 |
413 | ;; @@
414 |
415 | ;; **
416 | ;;; ### Getting to the core
417 | ;;; In the `alpha` namespace, call the `println` function correctly.
418 | ;; **
419 |
420 | ;; @@
421 |
422 | ;; @@
423 |
424 | ;; **
425 | ;;; ### A less empty namespace
426 | ;;; Create a new namespace `beta` using `ns`. Try calling a common function like `println`. Why does it work now?
427 | ;; **
428 |
429 | ;; @@
430 |
431 | ;; @@
432 |
433 | ;; **
434 | ;;; ### File it away
435 | ;;; Create a new Clojure source file for the namespace `student.dialect`, with the appropriate `ns` declaration.
436 | ;;;
437 | ;;; In this file, define a function canadianize that takes a string and appends ", eh?"
438 | ;; **
439 |
440 | ;; **
441 | ;;;
442 | ;; **
443 |
444 | ;; **
445 | ;;; ### Loading from files
446 | ;;; In the REPL below, load your new namespace and call the `canadianize` function.
447 | ;; **
448 |
449 | ;; @@
450 |
451 | ;; @@
452 |
453 | ;; **
454 | ;;; ### Modifying sources
455 | ;;; Modify your source file to make the `clojure.string` namespace available under the alias `str` in the `student.dialect` namespace.
456 | ;;;
457 | ;;; Modify the `canadianize` function to strip a trailing period off its input. Use `clojure.string/replace`.
458 | ;; **
459 |
460 | ;; **
461 | ;;; ### Reloading
462 | ;;; In the REPL below, reload your source file and call the improved `canadianize` function.
463 | ;; **
464 |
465 | ;; @@
466 |
467 | ;; @@
468 |
469 | ;; **
470 | ;;; ## Lab Solutions
471 | ;;;
472 | ;;; ### Entering a namespace
473 | ;; **
474 |
475 | ;; @@
476 | (in-ns 'alpha)
477 | ;; @@
478 |
479 | ;; **
480 | ;;; ### An empty namespace
481 | ;; **
482 |
483 | ;; @@
484 | (println "Hello, World!")
485 | ;; @@
486 |
487 | ;; **
488 | ;;; The `println` function is defined in the `clojure.core` namespace, which is not automatically referred into new namespaces by `in-ns`.
489 | ;;;
490 | ;;; ### Getting to the core
491 | ;; **
492 |
493 | ;; @@
494 | (clojure.core/println "Hello, World!")
495 | ;; @@
496 |
497 | ;; **
498 | ;;; ### A less empty namespace
499 | ;; **
500 |
501 | ;; @@
502 | (ns beta)
503 | (println "Hello, World!")
504 | ;; @@
505 |
506 | ;; **
507 | ;;; `ns` automatically refers all symbols from `clojure.core` into the new namespace.
508 | ;;;
509 | ;;; ### File it away
510 | ;; **
511 |
512 | ;; **
513 | ;;; ```clojure
514 | ;;; ;; SOLUTION
515 | ;;; ;; in $CLASSPATH/student/dialect.clj
516 | ;;; (ns student.dialect)
517 | ;;;
518 | ;;; (defn canadianize [sentence]
519 | ;;; (str sentence ", eh?"))
520 | ;;; ```
521 | ;; **
522 |
523 | ;; **
524 | ;;; ### Loading from files
525 | ;; **
526 |
527 | ;; @@
528 | (require 'student.dialect)
529 | (student.dialect/canadianze "Nice weather today.")
530 | ;; @@
531 |
532 | ;; **
533 | ;;; ### Modifying sources
534 | ;; **
535 |
536 | ;; **
537 | ;;; ```clojure
538 | ;;; ;; SOLUTION
539 | ;;; ;; in $CLASSPATH/student/dialect.clj
540 | ;;; (ns student.dialect
541 | ;;; (:require [clojure.string :as str]))
542 | ;;;
543 | ;;; (defn canadianize
544 | ;;; [sentence]
545 | ;;; (str/replace sentence #"\.$" ", eh?"))
546 | ;;; ```
547 | ;; **
548 |
549 | ;; **
550 | ;;; ### Reloading
551 | ;; **
552 |
553 | ;; @@
554 | (require 'student.dialect :reload)
555 | (student.dialect/canadianize "Nice weather today.")
556 | ;; @@
557 |
558 | ;; **
559 | ;;;
560 | ;; **
561 |
562 | ;; **
563 | ;;;
564 | ;; **
565 |
566 | ;; **
567 | ;;; ###
568 | ;; **
569 |
570 | ;; **
571 | ;;;
572 | ;; **
573 |
574 | ;; **
575 | ;;;
576 | ;; **
577 |
578 | ;; **
579 | ;;;
580 | ;;; ## Navigation
581 | ;;;
582 | ;;; * [Up (Home)](/worksheet.html?filename=src/cljlab/start.clj)
583 | ;;; * [Previous (Flow Control)](/worksheet.html?filename=src/cljlab/flowcontrol.clj)
584 | ;;; * [Next (Sequences)](/worksheet.html?filename=src/cljlab/sequences.clj)
585 | ;; **
586 |
--------------------------------------------------------------------------------
/src/cljlab/ordered-collections.clj:
--------------------------------------------------------------------------------
1 | ;; gorilla-repl.fileformat = 1
2 |
3 | ;; **
4 | ;;; # Ordered Collections
5 | ;; **
6 |
7 | ;; **
8 | ;;; Clojure collections "collect" values into compound values. There are four key Clojure collection types: vectors, lists, sets, and maps. Of those four collection types, vectors and lists are ordered.
9 | ;;;
10 | ;;; ## Vectors
11 | ;;;
12 | ;;; Vectors are an indexed, sequential data structure. Vectors are represented with `[ ]` like this:
13 | ;;;
14 | ;; **
15 |
16 | ;; @@
17 | [1 2 3]
18 | ;; @@
19 |
20 | ;; **
21 | ;;; ### Indexed access
22 | ;;;
23 | ;;; "Indexed" means that elements of a vector can be retrieved by index. In Clojure (as in Java), indexes start at 0, not 1. Use the `get` function to retrieve an element at an index:
24 | ;; **
25 |
26 | ;; @@
27 | (get ["abc" false 99] 0)
28 | ;; @@
29 |
30 | ;; @@
31 | (get ["abc" false 99] 1)
32 | ;; @@
33 |
34 | ;; **
35 | ;;; Calling `get` with an invalid index returns nil:
36 | ;; **
37 |
38 | ;; @@
39 | (get ["abc" false 99] 14)
40 | ;; @@
41 |
42 | ;; **
43 | ;;;
44 | ;; **
45 |
46 | ;; **
47 | ;;; ### count
48 | ;;;
49 | ;;; All Clojure collections can be counted:
50 | ;; **
51 |
52 | ;; @@
53 | (count [1 2 3])
54 | ;; @@
55 |
56 | ;; **
57 | ;;; ### Constructing
58 | ;;;
59 | ;;; In addition to using the literal `[ ]` syntax, Clojure collections can be created with the `vector` function:
60 | ;; **
61 |
62 | ;; @@
63 | (vector 1 2 3)
64 | ;; @@
65 |
66 | ;; **
67 | ;;; ### Adding elements
68 | ;;;
69 | ;;; Elements are added to a vector with `conj` (short for conjoin). Elements are always added to a vector at the end:
70 | ;; **
71 |
72 | ;; @@
73 | (conj [1 2 3] 4 5 6)
74 | ;; @@
75 |
76 | ;; **
77 | ;;; ### Immutability
78 | ;;;
79 | ;;; Clojure collections share important properties of simple values like strings and numbers, such as immutability and equality comparison by value.
80 | ;;;
81 | ;;; For example, lets create a vector and modify it with `conj`.
82 | ;; **
83 |
84 | ;; @@
85 | (def v [1 2 3])
86 | (conj v 4 5 6)
87 | ;; @@
88 |
89 | ;; **
90 | ;;; Here `conj` returned a new vector but if we examine the original vector, we see it's unchanged:
91 | ;; **
92 |
93 | ;; @@
94 | v
95 | ;; @@
96 |
97 | ;; **
98 | ;;; Any function that "changes" a collection returns a new instance. Your program will need to remember or pass along the changed instance to take advantage of it.
99 | ;;;
100 | ;;; ## Lists
101 | ;;;
102 | ;;; Lists are sequential linked lists that add new elements at the head of the list, instead of at the tail like vectors.
103 | ;;;
104 | ;;; ### Constructing
105 | ;;;
106 | ;;; Because lists are evaluated by invoking the first element as a function, we must quote a list to prevent evaluation:
107 | ;;;
108 | ;; **
109 |
110 | ;; @@
111 | (def cards '(10 :ace :jack 9))
112 | ;; @@
113 |
114 | ;; **
115 | ;;; Lists are not indexed so they must be walked using `first` and `rest`.
116 | ;; **
117 |
118 | ;; @@
119 | (first cards) ;; 10
120 | (rest cards) ;; '(:ace :jack 9)
121 | ;; @@
122 |
123 | ;; **
124 | ;;; ### Adding elements
125 | ;;;
126 | ;;; `conj` can be used to add elements to a list just as with vectors. However, `conj` always adds elements where it can be done in constant time for the data structure. In the case of lists, elements are added at the front:
127 | ;; **
128 |
129 | ;; @@
130 | (conj cards :queen)
131 | ;; (:queen 10 :ace :jack 9)
132 | ;; @@
133 |
134 | ;; **
135 | ;;; ### Stack access
136 | ;;;
137 | ;;; Lists can also be used as a stack with peek and pop:
138 | ;; **
139 |
140 | ;; @@
141 | (def stack '(:a :b))
142 | (peek stack) ;; :a
143 | (pop stack) ;; (:b)
144 | ;; @@
145 |
146 | ;; **
147 | ;;; ### Uses for lists
148 | ;;;
149 | ;;; * Efficient access to the first element
150 | ;;; * Efficiently remove the first element (`pop`)
151 | ;;; * Preserve a reverse order of inputs (last in, first out)
152 | ;;; * Simulating a stack
153 | ;; **
154 |
155 | ;; **
156 | ;;;
157 | ;;; ## Navigation
158 | ;;;
159 | ;;; * [Up (Home)](/worksheet.html?filename=src/cljlab/start.clj)
160 | ;;; * [Previous (Functions)](/worksheet.html?filename=src/cljlab/functions.clj)
161 | ;;; * [Next (Unordered Collections)](/worksheet.html?filename=src/cljlab/unordered-collections.clj)
162 | ;;;
163 | ;; **
164 |
--------------------------------------------------------------------------------
/src/cljlab/polymorphism.clj:
--------------------------------------------------------------------------------
1 | ;; gorilla-repl.fileformat = 1
2 |
3 | ;; **
4 | ;;; # Clojure Polymorphism
5 | ;;;
6 | ;;;
7 | ;; **
8 |
9 | ;; **
10 | ;;; ## Motivation
11 | ;;;
12 | ;;; There are many situations where it is useful to provide behavior that varies based on type or value. Clojure provides two different mechanisms to for conditional (polymorphic) behavior: protocols and multimethods.
13 | ;;;
14 | ;;; Also, Clojure provides two constructs that allow you to create new data "types": records (which we saw in collections earlier) and types.
15 | ;;;
16 | ;;; Clojure was created with some strong opinions in this area:
17 | ;;;
18 | ;;; * Only derive from interfaces, never from implementations
19 | ;;; * All generic methods should be defined in interfaces
20 | ;;; * Polymorphism doesn't require inheritance
21 | ;;; * Data is still immutable
22 | ;;; * No data hiding (aka encapsulation)
23 | ;;;
24 | ;;; ### What does "type" mean?
25 | ;;;
26 | ;;; "What is the type (class) of object x?"
27 | ;;; * `(class x)` or `(type x)`
28 | ;;;
29 | ;;; "Foo is a type (class)"
30 | ;;; * `(defrecord Foo ...)` or `(deftype Foo ...)`
31 | ;;; * or Java `public class Foo { ... }`
32 | ;;; * Java primitive types - `long`, `double`, arrays, etc
33 | ;;;
34 | ;;; ## Protocols
35 | ;;;
36 | ;;; Protocols define an abstract behavioral contract. Protocols create a named group of generic functions. Each function has (only) parameters and doc strings, no implementation.
37 | ;;;
38 | ;;; Protocols are polymorphic (choose the implementation) based on the type of the first argument (like methods in Java). Each protocol function must have at least one argument (the one used for dispatch) - equivalent to `this` in Java.
39 | ;;;
40 | ;;; ### defprotocol
41 | ;; **
42 |
43 | ;; @@
44 | (defprotocol MyProtocol
45 | "A doc string for MyProtocol abstraction"
46 | (bar [q r] "bar docs")
47 | (baz [q] "baz docs"))
48 | ;; @@
49 |
50 | ;; **
51 | ;;; Define a protocol named MyProtocol (in the current namespace) with a protocol docstring and functions `bar` and `baz`. These functions both dispatch based on the type of `q`.
52 | ;; **
53 |
54 | ;; **
55 | ;;; ### Protocol dispatch
56 | ;;;
57 | ;;; `defprotocol` creates generic functions. These are normal functions, just like `defn`. They are invoked just like any other Clojure function.
58 | ;; **
59 |
60 | ;; @@
61 | (defprotocol Describe
62 | (desc [self]))
63 |
64 | (desc thing) ; Invoke it like this
65 |
66 | (.desc thing) ; Not this
67 |
68 | ;; Similar to Java: thing.desc()
69 | ;; @@
70 |
71 | ;; **
72 | ;;; ### Extending Protocols to Types
73 | ;;;
74 | ;;; What if we want to add protocols to an existing type (for example, Java types like `String`)?
75 | ;;;
76 | ;;; This is sometimes called the "Expression Problem". The problem is how to enable extending either the set of concrete types or the set of generic operations while existing code continues to work.
77 | ;;;
78 | ;;; Common solutions won't work:
79 | ;;; * Inheritance - can't inherit from `String`
80 | ;;; * Multiple inheritance - complex, not allowed in Java
81 | ;;; * Wrapping - complex, breaks type and equality
82 | ;;; * Open classes - no namespacing, error-prone
83 | ;;; * Conditionals - complex, not extensible without changing code
84 | ;;;
85 | ;;; ### Protocol extension
86 | ;;;
87 | ;;; Clojure allows extending any protocol to any type, including final Java classes. The type is not modified in any way. Implementations can be extended to both nil and Object.
88 | ;;;
89 | ;;; ### `extend-type` and `extend-protocol`
90 | ;;;
91 | ;;; Extensions are specified with `extend-type` or `extend-protocol`.
92 | ;; **
93 |
94 | ;; @@
95 | (extend-type SomeType ; 1 type, many protocols
96 | SomeProtocol
97 | (some-method [...] ...)
98 | AnotherProtocol
99 | (another-method [...] ...))
100 |
101 | (extend-protocol SomeProtocol ; 1 protocol, many types
102 | SomeType
103 | (some-method [...] ...)
104 | AnotherType
105 | (some-method [...] ...))
106 | ;; @@
107 |
108 | ;; **
109 | ;;; ### `extend-type example
110 | ;; **
111 |
112 | ;; @@
113 | ; java.lang.String does not implement Describe
114 | (desc "a")
115 |
116 | ; IllegalArgumentException No implementation of
117 | ; method: :desc of protocol: #'user/Describe
118 | ; found for class: java.lang.String
119 |
120 | (satisfies? Describe "a")
121 | ;;=> false
122 |
123 | ; extend Describe to java.lang.String
124 | (extend-type String
125 | Describe
126 | (desc [s] s))
127 |
128 | (satisfies? Describe "a")
129 | ;;=> true
130 |
131 | ; try again...
132 | (desc "a")
133 | ;;=> "a"
134 | ;; @@
135 |
136 | ;; **
137 | ;;; ### Reifying protocols
138 | ;;;
139 | ;;; `reify` builds anonymous type and instance on the fly, conceptually similar to anonymous functions or anonymous inner classes in Java. Function bodies are closures.
140 | ;; **
141 |
142 | ;; @@
143 | (def r (let [x 42]
144 | (reify Describe
145 | (desc [_] (str "describe with " x)))))
146 | ;;=> #user/r
147 |
148 | (desc r)
149 | ;;=> "describe with 42"
150 | ;; @@
151 |
152 | ;; **
153 | ;;; ## Multimethods
154 | ;;;
155 | ;;; Protocols are limited to single-argument dispatch on the type of the first argument. Multimethods support multi-argument dispatch on any criteria of all of the arguments, so it is much more flexible.
156 | ;; **
157 |
158 | ;; @@
159 | (defmulti reaction
160 | ;; 2-argument dispatch function:
161 | (fn [a b] [(:species a) (:species b)]))
162 |
163 | (defmethod reaction [:hero :monster] ; match criteria
164 | [hero monster] ; function parameters
165 | (str hero " fights " monster)) ; function body
166 |
167 | (defmethod reaction [:monster :hero]
168 | [monster hero]
169 | (str monster " eats " hero))
170 |
171 | (defmethod reaction [:monster :monster]
172 | [monster1 monster2]
173 | (str monster1 " plays with " monster2))
174 |
175 | (defmethod reaction [:hero :hero]
176 | [hero1 hero2]
177 | (str hero1 " taunts " hero2))
178 | ;; @@
179 |
180 | ;; **
181 | ;;; ### Custom dispatch
182 | ;;;
183 | ;;;
184 | ;; **
185 |
186 | ;; @@
187 | (defmulti shape count)
188 |
189 | (defmethod shape 3 [points] "triangle")
190 | (defmethod shape 4 [points] "rectangle")
191 | (defmethod shape 5 [points] "pentagon")
192 | (defmethod shape 6 [points] "hexagon")
193 | (defmethod shape :default [n] "who cares?")
194 |
195 | (shape [[0 0], [0 5], [5 0]]) ;;=> "triangle"
196 | (shape [[0 0], [0 5], [5 0], [5 5]]) ;;=> "rectangle"
197 | (shape []) ;;=> "who cares?"
198 | ;; @@
199 |
200 | ;; **
201 | ;;; ### Multimethods vs Protocols
202 | ;;;
203 | ;;; | | Multimethods | Protocols |
204 | ;;; |-|--------------|-----------|
205 | ;;; | Extensible | yes | yes|
206 | ;;; | Java interop story | Vars | interfaces |
207 | ;;; | Dispatch on arguments | any number | only first |
208 | ;;; | Dispatch function | arbitrary | only type |
209 | ;;; | Method grouping | no | yes |
210 | ;;; | High performance | no | yes |
211 | ;;;
212 | ;; **
213 |
214 | ;; **
215 | ;;; ## Records
216 | ;;;
217 | ;;; As we discussed in the Collections section, records create entities with explicit types, not just generic maps. Records can implement both protocols and interfaces directly at definition time:
218 | ;; **
219 |
220 | ;; @@
221 | (defrecord Car [make model year]) ; named type with fields
222 | ;;=> user.Car
223 |
224 | (def car (->Car "Dodge" "Omni" 1980)) ; instantiation
225 | ;;=> #'user/car
226 |
227 | (:year car) ; field access
228 | ;;=> 1980
229 | ;; @@
230 |
231 | ;; **
232 | ;;; ### Records are classes
233 | ;;;
234 | ;;;
235 | ;; **
236 |
237 | ;; @@
238 | (def car (Car. "Dodge" "Omni" 1980)) ; Java constructor
239 | ;;=> #'user/car
240 |
241 | (.-year car) ; fields are public & final
242 | ;;=> 1980
243 |
244 | (class car) ; ordinary class
245 | ;;=> user.Car
246 |
247 | (supers (class car)) ; lots of built-in functionality
248 |
249 | ;;=> #{clojure.lang.IObj clojure.lang.IKeywordLookup java.util.Map
250 | ;; clojure.lang.IPersistentMap clojure.lang.IMeta java.lang.Object
251 | ;; java.lang.Iterable clojure.lang.ILookup clojure.lang.Seqable
252 | ;; clojure.lang.Counted clojure.lang.IPersistentCollection
253 | ;; clojure.lang.Associative}
254 | ;; @@
255 |
256 | ;; **
257 | ;;; ### Implementing protocols on records
258 | ;;;
259 | ;;; Protocols (and Java interfaces) can be implemented directly in `defrecord`. Method implementation bodies can access record fields directly but *do not* close over the lexical environment. If a record does not implement all of the protocol methods, undefined ones will throw `AbstractMethodError`.
260 | ;; **
261 |
262 | ;; @@
263 | ; specify protocol(s) directly inline
264 | (defrecord Car [make model year]
265 | Describe
266 | (desc [self] (str year " " make " " model)))
267 |
268 | (def car (->Car "Dodge" "Omni" 1980))
269 | (desc car)
270 | ;;=> "1980 Dodge Omni"
271 | ;; @@
272 |
273 | ;; **
274 | ;;; ### Using protocols and records
275 | ;; **
276 |
277 | ;; @@
278 | (defprotocol Player "A rock/paper/scissors player"
279 | (choose [p] "return :rock, :paper or :scissors")
280 | (update-player [p me you]
281 | "return a new player based on what you and I did"))
282 |
283 | (defrecord Stubborn [choice]
284 | Player ; implement Player protocol
285 | (choose [_] choice) ; always play the choice
286 | (update-player [this _ _] this)) ; never change
287 |
288 | (defrecord Mean [last-win] ; last thing that won for me
289 | Player
290 | (choose [_]
291 | (if last-win ; play last-win or random
292 | last-win
293 | (random-choice)))
294 | (update-player [_ me you]
295 | ;; reuse last choice, or switch to random
296 | (->Mean (when (i-won? me you) me))))
297 | ;; @@
298 |
299 | ;; **
300 | ;;; ## `deftype`
301 | ;;;
302 | ;;; `deftype` is used for (usually) advanced use cases where you want a new type with custom behavior. `deftype` looks like `defrecord` but provides *no* default behavior. Additionally, fields can be mutable (DANGER!).
303 | ;;;
304 | ;;;
305 | ;; **
306 |
307 | ;; @@
308 | (deftype Point [x y]) ; named type with fields
309 | ;;=> user.Point
310 |
311 | (def p (->Point 1 2)) ; constructor
312 | ;;=> #'user/p ; (but no map->Point)
313 |
314 | (.-x p) ; ordinary field access
315 | ;;=> 1 ; (but no keyword lookup)
316 |
317 | (class p) ; ordinary class
318 | ;;=> user.Point
319 |
320 | (supers (class p)) ; an (almost) blank slate
321 | ;;=> #{java.lang.Object clojure.lang.IType}
322 | ;; @@
323 |
324 | ;; **
325 | ;;; # LAB: Rock, Paper, Scissors
326 | ;;;
327 | ;;; In this lab, we will write programs to play the classic game of [Rock, Paper, Scissors](http://en.wikipedia.org/wiki/Rock-paper-scissors). The rules are simple:
328 | ;;;
329 | ;;; * Rock beats Scissors
330 | ;;; * Scissors beats Paper
331 | ;;; * Paper beats Rock
332 | ;;;
333 | ;;; (For each section, the solutions are available at the bottom.)
334 | ;;;
335 | ;;; ## World domination
336 | ;;;
337 | ;;; Define a function dominates that takes a keyword argument and returns the keyword naming the thing that beats it.
338 | ;;;
339 | ;;; Hint: remember that data structures are functions.
340 | ;;;
341 | ;;; ## Choices, choices
342 | ;;;
343 | ;;; Define a vector of the possible choices, reusing the definition of dominates.
344 | ;;;
345 | ;;; Hint: the `keys` function returns a sequence of the keys in a map.
346 | ;;;
347 | ;;; ## Winners and losers
348 | ;;;
349 | ;;; Define a function winner that takes two players' choices and returns the winner, or nil for a tie.
350 | ;;;
351 | ;;; ## Draws and ties
352 | ;;;
353 | ;;; Define two predicates:
354 | ;;;
355 | ;;; * `draw?` takes two players' choices and returns true if they are a draw
356 | ;;; * `iwon?` takes two players' choices and returns true if the first player won
357 | ;;;
358 | ;;; ## The players
359 | ;;;
360 | ;;; All the players will conform to a `Player` protocol. It should have two methods:
361 | ;;;
362 | ;;; * `choose` takes a player and returns that player's choice
363 | ;;; * `update-player` takes a player, that player's last choice, and the other player's last choice, returning a new `Player` for the next round
364 | ;;;
365 | ;;; Define the `Player` protocol.
366 | ;;;
367 | ;;; ## Random player
368 | ;;;
369 | ;;; Define a `Random` player who always picks at random and never changes strategy based on what the other player is doing.
370 | ;;;
371 | ;;; Hint: Clojure's `rand-nth` function picks a random element from a collection.
372 | ;;;
373 | ;;; ## Stubborn player
374 | ;;;
375 | ;;; Define a Stubborn player who is initialized with a choice and sticks with it no matter what.
376 | ;;;
377 | ;;; ## Mean player
378 | ;;;
379 | ;;; Define a Mean player, who is slightly more subtle. The mean player sticks with what worked last time if it won, or plays at random following a loss.
380 | ;;;
381 | ;;; ## Playing a game
382 | ;;;
383 | ;;; Define a `game` function with three arguments: two players and a number of rounds. The game should return the two player's scores in a map.
384 | ;;;
385 | ;;; This can be nicely represented as a `loop` with five variables:
386 | ;;;
387 | ;;; 1. Player One
388 | ;;; 2. Player Two
389 | ;;; 3. Player One's current score
390 | ;;; 4. Player Two's current score
391 | ;;; 5. The number of rounds remaining
392 | ;;;
393 | ;;; Try some games with various combinations of players. Do the results match your intuition?
394 | ;;;
395 | ;;; Examples:
396 | ;; **
397 |
398 | ;; @@
399 | (game (->Stubborn :rock) (->Stubborn :scissors) 100)
400 | ;;=> {:p1 100, :p2 0}
401 |
402 | (game (->Random) (->Random) 100)
403 | ;;=> {:p1 34, :p2 25}
404 |
405 | (game (->Stubborn :rock) (->Mean nil) 100)
406 | ;;=> {:p1 5, :p2 93}
407 | ;; @@
408 |
409 | ;; **
410 | ;;; # LAB SOLUTIONS
411 | ;;;
412 | ;;; ## World domination
413 | ;; **
414 |
415 | ;; @@
416 | (def dominates
417 | {:rock :paper
418 | :scissors :rock
419 | :paper :scissors})
420 | ;; @@
421 |
422 | ;; **
423 | ;;; ## Choices, choices
424 | ;; **
425 |
426 | ;; @@
427 | (def choices (vec (keys dominates)))
428 | ;; @@
429 |
430 | ;; **
431 | ;;; ## Winners and losers
432 | ;; **
433 |
434 | ;; @@
435 | (defn winner [p1-choice p2-choice]
436 | (cond
437 | (= p1-choice p2-choice) nil
438 | (= (dominates p1-choice) p2-choice) p2-choice
439 | :else p1-choice))
440 | ;; @@
441 |
442 | ;; **
443 | ;;; ## Draws and ties
444 | ;; **
445 |
446 | ;; @@
447 | (defn draw? [me you] (= me you))
448 |
449 | (defn iwon? [me you] (= (winner me you) me))
450 | ;; @@
451 |
452 | ;; **
453 | ;;; ## The players
454 | ;; **
455 |
456 | ;; @@
457 | (defprotocol Player
458 | (choose [p])
459 | (update-player [p me you]))
460 | ;; @@
461 |
462 | ;; **
463 | ;;; ## Random player
464 | ;; **
465 |
466 | ;; @@
467 | (defrecord Random []
468 | Player
469 | (choose [_] (rand-nth choices))
470 | (update-player [this me you] this))
471 | ;; @@
472 |
473 | ;; **
474 | ;;; ## Stubborn player
475 | ;; **
476 |
477 | ;; @@
478 | (defrecord Stubborn [choice]
479 | Player
480 | (choose [_] choice)
481 | (update-player [this me you] this))
482 | ;; @@
483 |
484 | ;; **
485 | ;;; ## Mean player
486 | ;; **
487 |
488 | ;; @@
489 | (defrecord Mean [last-winner]
490 | Player
491 | (choose [_]
492 | (if last-winner last-winner (rand-nth choices)))
493 | (update-player [_ me you]
494 | (->Mean (when (iwon? me you) me))))
495 | ;; @@
496 |
497 | ;; **
498 | ;;; ## Playing a game
499 | ;; **
500 |
501 | ;; @@
502 | (defn game
503 | [p1 p2 rounds]
504 | (loop [p1 p1
505 | p2 p2
506 | p1-score 0
507 | p2-score 0
508 | rounds rounds]
509 | (if (pos? rounds)
510 | (let [p1-choice (choose p1)
511 | p2-choice (choose p2)
512 | result (winner p1-choice p2-choice)]
513 | (recur
514 | (update-player p1 p1-choice p2-choice)
515 | (update-player p2 p2-choice p1-choice)
516 | (+ p1-score (if (= result p1-choice) 1 0))
517 | (+ p2-score (if (= result p2-choice) 1 0))
518 | (dec rounds)))
519 | {:p1 p1-score :p2 p2-score})))
520 | ;; @@
521 |
522 | ;; **
523 | ;;;
524 | ;;; ## Navigation
525 | ;;;
526 | ;;; * [Up (Home)](/worksheet.html?filename=src/cljlab/start.clj)
527 | ;;; * [Previous (Sequences)](/worksheet.html?filename=src/cljlab/sequences.clj)
528 | ;;; * [Next (State and Concurrency)](/worksheet.html?filename=src/cljlab/state.clj)
529 | ;; **
530 |
531 | ;; **
532 | ;;;
533 | ;; **
534 |
--------------------------------------------------------------------------------
/src/cljlab/start.clj:
--------------------------------------------------------------------------------
1 | ;; gorilla-repl.fileformat = 1
2 |
3 | ;; **
4 | ;;; # Welcome to Clojure!
5 | ;;;
6 | ;;;
7 | ;; **
8 |
9 | ;; **
10 | ;;; ## How does this work?
11 | ;;;
12 | ;;; You are currently reading a page hosted by [Gorilla REPL](http://gorilla-repl.org/). A "REPL" is the **Read-Eval-Print-Loop**--the beating heart inside any LISP. The Gorilla REPL creates interactive web pages that are a mix of text (in Markdown) and code (live REPLs).
13 | ;;;
14 | ;;; As you follow along in this course, you can
15 | ;;;
16 | ;;; * Evaluate any code block with Shift-Enter, or
17 | ;;; * Save any page with Ctrl-G Ctrl-S.
18 | ;;;
19 | ;;; For the full set of commands, type Ctrl-G Ctrl-G, or use the drop-down menu in the upper-right corner.
20 | ;;;
21 | ;;; Because this page is editable, it will switch to edit mode when you select a text segment. This is somewhat annoying, and it is an area we are working to improve, but for now, please bear with us.
22 | ;;;
23 | ;;; Also note, to avoid editing a block with a link, right-click on each link and select "Open in New Tab".
24 | ;;;
25 | ;; **
26 |
27 | ;; **
28 | ;;; ## Table of Contents
29 | ;;;
30 | ;;; 1. [Syntax](/worksheet.html?filename=src/cljlab/syntax.clj)
31 | ;;; 2. [Functions](/worksheet.html?filename=src/cljlab/functions.clj)
32 | ;;; 3. [Ordered Collections](/worksheet.html?filename=src/cljlab/ordered-collections.clj)
33 | ;;; 4. [Unordered Collections](/worksheet.html?filename=src/cljlab/unordered-collections.clj)
34 | ;;; 5. [Flow Control](/worksheet.html?filename=src/cljlab/flowcontrol.clj)
35 | ;;; 6. [Namespaces](/worksheet.html?filename=src/cljlab/namespaces.clj)
36 | ;;; 7. [Sequences](/worksheet.html?filename=src/cljlab/sequences.clj)
37 | ;;; 8. [Polymorphism](/worksheet.html?filename=src/cljlab/polymorphism.clj)
38 | ;;; 9. [State](/worksheet.html?filename=src/cljlab/state.clj)
39 | ;;;
40 | ;; **
41 |
42 | ;; @@
43 |
44 | ;; @@
45 |
--------------------------------------------------------------------------------
/src/cljlab/state.clj:
--------------------------------------------------------------------------------
1 | ;; gorilla-repl.fileformat = 1
2 |
3 | ;; **
4 | ;;; # State and Concurrency
5 | ;;;
6 | ;;; ### Identity, Value, State
7 | ;;;
8 | ;;; * Identity - a logical entity: wife, today, employer, shipping address
9 | ;;; * Value - immutable data: 5, "Bob", [0 1 2]
10 | ;;; * State - the value of an identity at a given time
11 | ;;;
12 | ;;; Example: "today is April 15, 2015"
13 | ;;; * identity = today
14 | ;;; * value = April 15, 2015
15 | ;;; * state of today = April 15, 2015
16 | ;;;
17 | ;;; ### OOP with mutable state
18 | ;;;
19 | ;;; * Identities are pointers to locations in memory
20 | ;;; * Objects changed in-place
21 | ;;; * Updating state means overwriting memory
22 | ;;; * Need to protect reads/writes
23 | ;;; * No language support for coordinating changes
24 | ;;; * Locking, deadlocks, and pain
25 | ;;;
26 | ;;; ### Clojure's approach
27 | ;;;
28 | ;;; * Identities are managed references to immutable values
29 | ;;; * Nothing changed in-place
30 | ;;; * References provide read/write protection
31 | ;;; * Language-level constructs to manage change
32 | ;;; * No locking in user code
33 | ;;;
34 | ;; **
35 |
36 | ;; **
37 | ;;; ## Conceptual Model
38 | ;;;
39 | ;;; ### Modeling Change
40 | ;;;
41 | ;;; 
42 | ;;;
43 | ;;; 
44 | ;;;
45 | ;;; 
46 | ;;;
47 | ;;; 
48 | ;;;
49 | ;;; 
50 | ;;;
51 | ;;;
52 | ;;;
53 | ;;;
54 | ;;;
55 | ;; **
56 |
57 | ;; **
58 | ;;; ### Uniform State Transition Model
59 | ;;;
60 | ;;; * `(change-fn reference function args*)`
61 | ;;; * Calls `function` on old state + args
62 | ;;; * Function returns new state
63 | ;;; * Different `change-fn` functions for different behavior
64 | ;;; * `(deref reference)`
65 | ;;; * Shorthand: @reference (this is called a "reader macro")
66 | ;;; * Returns snapshot of current state
67 | ;;;
68 | ;;; ### Mutable Reference Types
69 | ;;;
70 | ;;; * Synchronous
71 | ;;; * Uncoordinated: Var, Atom
72 | ;;; * Coordinated: Ref
73 | ;;; * Asynchronous
74 | ;;; * Write-many: Agent
75 | ;;; * Write-once: Future, Promise (not really reference types)
76 | ;;;
77 | ;;; ## Atoms
78 | ;;;
79 | ;;; Atoms are the simplest of the reference types - they allow us to share a stable identity for a single value across threads. Changes become visible to all threads at the same time.
80 | ;; **
81 |
82 | ;; @@
83 | (def tick (atom 1))
84 | ;;=> #'user/tick
85 |
86 | (deref tick)
87 | ;;=> 1
88 |
89 | (swap! tick inc)
90 | ;;=> 2
91 |
92 | @tick
93 | ;;=> 2
94 | ;; @@
95 |
96 | ;; **
97 | ;;; ### Atom Guarantees
98 | ;;;
99 | ;;; * Change is *synchronous* on caller thread
100 | ;;; * Changes are *atomic*
101 | ;;; * No locking
102 | ;;; * No deadlocks
103 | ;;;
104 | ;;; ### Atom Caveats
105 | ;;;
106 | ;;; * Values must be immutable
107 | ;;; * Cannot atomically update more than one at a time
108 | ;;; * Spinning compare-and-set
109 | ;;; * Update functions should be quick
110 | ;;; * Update function may be called more than once
111 | ;;; * Must avoid side effects!
112 | ;;;
113 | ;; **
114 |
115 | ;; **
116 | ;;; ## Refs
117 | ;;;
118 | ;;; * Share identities across threads (like atoms)
119 | ;;; * Coordinated change among multiple identities (different than atoms)
120 | ;;; * Consistent view of the whole "ref" world
121 | ;; **
122 |
123 | ;; @@
124 | (def a (ref 1))
125 | (def b (ref 10))
126 |
127 | (dosync
128 | (alter a inc)
129 | (alter b + 10))
130 |
131 | @a ;=> 2
132 | @b ;=> 20
133 | ;; @@
134 |
135 | ;; **
136 | ;;;
137 | ;; **
138 |
139 | ;; **
140 | ;;; ### Ref Guarantees
141 | ;;;
142 | ;;; * Change is *synchronous* on caller thread
143 | ;;; * Change can only occur in a transaction
144 | ;;; * Every transaction is *atomic* and *isolated*
145 | ;;; * No locking in user code
146 | ;;; * Internal locking & deadlock prevention
147 | ;;;
148 | ;;; ### Within a Transaction
149 | ;;;
150 | ;;; * Consistent snapshot of "ref world" from point where transaction started
151 | ;;; * Transaction can see changes it has made
152 | ;;;
153 | ;;; ### Ref Caveats
154 | ;;;
155 | ;;; * Values must be immutable
156 | ;;; * Transactions are speculative
157 | ;;; * Body may be called more than once
158 | ;;; * Must avoid side effects!
159 | ;;;
160 | ;;; ### No Read Tracking
161 | ;;;
162 | ;;; * Reading a Ref does not prevent other transactions from changing it
163 | ;;; * Transaction does not see changes made by other transactions
164 | ;;; * Enlist reads in transaction for read tracking with `ensure`
165 | ;;;
166 | ;;; ### `ensure`
167 | ;;;
168 | ;;; In this example, the fee may change during the life of the transaction and the transaction will only see the starting value.
169 | ;; **
170 |
171 | ;; @@
172 | ;; savings and fee are refs
173 | (dosync
174 | (alter savings + @fee))
175 | ;; @@
176 |
177 | ;; **
178 | ;;; Use ensure to guarantee that if the fee changes, the transaction will fail and retry:
179 | ;; **
180 |
181 | ;; @@
182 | (dosync
183 | (alter savings + (ensure fee)))
184 | ;; @@
185 |
186 | ;; **
187 | ;;; ### `commute`
188 | ;;;
189 | ;;; * Like `alter`, but provides more concurrency
190 | ;;; * Use when order of updates doesn't matter
191 | ;;; * Just a performance optimization over `alter`
192 | ;;;
193 | ;;;
194 | ;;;
195 | ;; **
196 |
197 | ;; @@
198 | (def counter (ref 1))
199 |
200 | (dosync (commute counter inc))
201 |
202 | ;; On another thread:
203 | (dosync (commute counter + 30))
204 | ;; @@
205 |
206 | ;; **
207 | ;;; ## Agents
208 | ;;;
209 | ;;; * Share identities across threads
210 | ;;; * Ensure an entity only does one thing at a time
211 | ;;; * Send messages between entities
212 | ;;; * Utilize all available CPU cores
213 | ;;;
214 | ;;; ### Agent Usage
215 | ;;;
216 | ;;;
217 | ;; **
218 |
219 | ;; @@
220 | (def a (agent 5))
221 |
222 | (send a + 10) ; returns immediately
223 | @a ; => still 5
224 |
225 | ;; Some time later:
226 | @a ; => 15
227 | ;; @@
228 |
229 | ;; **
230 | ;;; ### Agent Guarantees
231 | ;;;
232 | ;;; * Action occurs *asynchronously* on thread pool
233 | ;;; * Action called exactly once
234 | ;;; * Only one action per Agent at a time
235 | ;;; * Sends during an action
236 | ;;; * Occur *after* state has been updated
237 | ;;; * Do not occur if action throws an exception
238 | ;;;
239 | ;;; ### `send` vs `send-off`
240 | ;;;
241 | ;;; * `send`
242 | ;;; * Fixed-size thread pool
243 | ;;; * Actions should not block
244 | ;;; * For CPU-bound tasks
245 | ;;; * `send-off`
246 | ;;; * Variable-sized thread pool
247 | ;;; * Actions may block
248 | ;;; * For IO-bound tasks
249 | ;;;
250 | ;;; ### Agents are not actors
251 | ;;;
252 | ;;; * In-process only
253 | ;;; * Point-in-time perception is free
254 | ;;; * Send functions, not messages
255 | ;;;
256 | ;;; ### Agents and Transactions
257 | ;;;
258 | ;;; * Sends duringa transaction
259 | ;;; * An allowable side-effect
260 | ;;; * Occur *after* transaction is committed
261 | ;;; * Do not occur if transaction is aborted
262 | ;;;
263 | ;;; ## Vars
264 | ;;;
265 | ;;; * Thread-safe global identity
266 | ;;; * Optional dynamic scope/overrides
267 | ;;; * Binding overrides isolated to a single thread
268 | ;;;
269 | ;;; ### Var Guarantees
270 | ;;;
271 | ;;; * One global root binding
272 | ;;; * `alter-var-root` is *atomic* and *blocking*
273 | ;;; * With `^:dynamic`
274 | ;;; * Many thread-local bindings
275 | ;;; * Thread-local assignments
276 | ;;; * Dynamic scope
277 | ;;;
278 | ;;; ### Var Usage
279 | ;;;
280 | ;;;
281 | ;; **
282 |
283 | ;; @@
284 | (def foo 1)
285 | ;;=> #'user/foo
286 |
287 | (alter-var-root #'foo inc)
288 | ;;=> 2
289 |
290 | foo
291 | ;;=> 2
292 | ;; @@
293 |
294 | ;; **
295 | ;;; ### Dynamic Var Usage
296 | ;;;
297 | ;; **
298 |
299 | ;; @@
300 | (def ^:dynamic *foo* 5) ; root binding is 5
301 |
302 | (binding [*foo* 100] ; thread-local binding
303 | (println *foo*) ; => 100
304 | (set! *foo* 42) ; thread-local assignment
305 | (println *foo*)) ; => 42
306 |
307 | *foo* ; root binding still 5
308 | ;; @@
309 |
310 | ;; **
311 | ;;; ## Uniform State Transition Model
312 | ;;;
313 | ;;;
314 | ;; **
315 |
316 | ;; @@
317 | (swap! an-atom assoc :a "lucy")
318 |
319 | (dosync (alter a-ref assoc :a "lucy"))
320 |
321 | (send an-agent assoc :a "lucy")
322 |
323 | (alter-var-root #'a-var assoc :a "lucy")
324 | ;; @@
325 |
326 | ;; **
327 | ;;; ### Setting state without depending on previous value
328 | ;;;
329 | ;; **
330 |
331 | ;; @@
332 | (reset! an-atom 42)
333 |
334 | (dosync (ref-set a-ref 42))
335 |
336 | (send an-agent (constantly 42))
337 |
338 | (alter-var-root #'a-var (constantly 42))
339 | ;; @@
340 |
341 | ;; **
342 | ;;; ## Watches
343 | ;;;
344 | ;;; * Get notified when a reference changes
345 | ;;; * Supported on Atom, Ref, Agent, and Var
346 | ;;;
347 | ;;; ### Watch functions
348 | ;;;
349 | ;;; * A callback function for when change occurs
350 | ;;; * Arguments: key, reference, old, and new states
351 | ;;;
352 | ;; **
353 |
354 | ;; @@
355 | (defn my-watcher [key reference old-state new-state]
356 | (println "Watcher called for" key)
357 | (println "Old state:" old-state)
358 | (println "New state:" new-state))
359 | ;; @@
360 |
361 | ;; **
362 | ;;; ### `add-watch`
363 | ;;;
364 | ;;; * Arguments: reference, key, watch function
365 | ;; **
366 |
367 | ;; @@
368 | (add-watch r :foo my-watcher)
369 |
370 | (dosync (alter r inc))
371 | ;; Watcher called for :foo
372 | ;; Old state: 42
373 | ;; New state: 43
374 | ;;=> 43
375 | ;; @@
376 |
377 | ;; **
378 | ;;; ## Futures
379 | ;;;
380 | ;;; * Execute code in a background thread
381 | ;;; * Possibly with side effects
382 | ;;; * Block only when we ask for the result
383 | ;; **
384 |
385 | ;; @@
386 | (def f (future
387 | ;; body of expressions
388 | ))
389 | ;; body starts on background thread
390 |
391 | @f ; blocks until complete, returns result
392 | ;; @@
393 |
394 | ;; **
395 | ;;; ## Promises
396 | ;;;
397 | ;;; * Communicate a single value across threads
398 | ;;; * Deliver once from producer thread
399 | ;;; * Consumer(s) can wait until value becomes available
400 | ;;;
401 | ;; **
402 |
403 | ;; @@
404 | (def p (promise))
405 |
406 | ;; on another thread
407 | (deliver p 42)
408 |
409 | @p ; blocks until delivered
410 | ;; @@
411 |
412 | ;; **
413 | ;;; ### Inverting async
414 | ;; **
415 |
416 | ;; @@
417 | (def p (promise))
418 |
419 | (future
420 | ;; do something that takes time
421 | (deliver p 42))
422 |
423 | ;; do something else for a while
424 |
425 | @p ; blocks until delivered
426 | ;; @@
427 |
428 | ;; **
429 | ;;; ## Concurrency and the JVM
430 | ;;;
431 | ;;; * `java.util.concurrent` is available via interop
432 | ;;; * thread pools, locks, atomic, concurrent collections
433 | ;;; * Clojure fns are `java.util.concurrent.Callable` and `java.lang.Runnable`
434 | ;;; * Clojure's concurrency features are thread-agnostic
435 | ;;; * Use futures/agents to create threads
436 | ;;; * Or something else
437 | ;; **
438 |
439 | ;; **
440 | ;;;
441 | ;;; ## Navigation
442 | ;;;
443 | ;;; * [Up (Home)](/worksheet.html?filename=src/cljlab/start.clj)
444 | ;;; * [Previous (Polymorphism))](/worksheet.html?filename=src/cljlab/polymorphism.clj)
445 | ;;;
446 | ;; **
447 |
448 | ;; **
449 | ;;;
450 | ;; **
451 |
--------------------------------------------------------------------------------
/src/cljlab/syntax.clj:
--------------------------------------------------------------------------------
1 | ;; gorilla-repl.fileformat = 1
2 |
3 | ;; **
4 | ;;; # Clojure Syntax
5 | ;;;
6 | ;;; ## Literals
7 | ;;;
8 | ;;; Below are some examples of literal representations of common primitives in Clojure.
9 | ;;;
10 | ;;; The ";" creates a comment to the end of the line. Sometimes multiple semicolons are used to indicate header lines.
11 | ;; **
12 |
13 | ;; @@
14 | ;; Numeric types
15 | 42 ; Long - 64-bit integer (from -2^63 to 2^63-1)
16 | 6.022e23 ; Double - double-precision 64-bit IEEE 754 floating point
17 | 42N ; BigInt - arbitrary precision integer
18 | 1.0M ; BigDecimal - arbitrary precision fixed-point decimal
19 | 22/7 ; Ratio
20 |
21 | ;; Character types
22 | "hello" ; String
23 | \e ; Character
24 |
25 | ;; Other types
26 | nil ; null value
27 | true ; Boolean (also, false)
28 | #"[0-9]+" ; Regular expression
29 | :alpha ; Keyword
30 | :release/alpha ; Keyword with namespace
31 | map ; Symbol
32 | + ; Symbol - most punctuation allowed
33 | clojure.core/+ ; Namespaced symbol
34 | ;; @@
35 |
36 | ;; **
37 | ;;; All of the literals above are valid Clojure expressions.
38 | ;;;
39 | ;;; Clojure also includes literal syntax for four collections that can be used to combine Clojure expressions:
40 | ;; **
41 |
42 | ;; @@
43 | '(1 2 3) ; list
44 | [1 2 3] ; vector
45 | #{1 2 3} ; set
46 | {:a 1, :b 2} ; map
47 | ;; @@
48 |
49 | ;; **
50 | ;;; We'll talk about these in much greater detail later - for now it's enough to know that these four data structures can be used to create composite data.
51 | ;; **
52 |
53 | ;; **
54 | ;;; ## Evaluation
55 | ;; **
56 |
57 | ;; **
58 | ;;; Next we will consider how Clojure reads and evaluates expressions.
59 | ;;;
60 | ;;; ### Traditional Evaluation (Java)
61 | ;;;
62 | ;;; 
63 | ;;;
64 | ;;; In Java, source code (.java files) are read as characters by the compiler (javac), which produces bytecode (.class files) which can be loaded by the JVM.
65 | ;;;
66 | ;;; ### Clojure Evaluation
67 | ;;;
68 | ;;; 
69 | ;;;
70 | ;;; In Clojure, source code is read as characters by the Reader. The Reader may read the source either from .clj files or be given a series of expressions interactively. The Reader produces Clojure data. The Clojure compiler then produces the bytecode for the JVM.
71 | ;;;
72 | ;;; There are two important points here:
73 | ;;; 1. The unit of source code is a *Clojure expression*, not a Clojure source file. Source files are read as a series of expressions, just as if you typed those expressions interactively at the REPL.
74 | ;;; 2. Separating the Reader and the Compiler is a key separation that makes room for macros. Macros are special functions that take code (as data), and emit code (as data). Can you see where a loop for macro expansion could be inserted in the evaluation model?
75 | ;; **
76 |
77 | ;; **
78 | ;;; ### Structure vs Semantics
79 | ;;;
80 | ;;; Consider a Clojure expression:
81 | ;;;
82 | ;;; 
83 | ;;;
84 | ;;; This diagram illustrates the difference between syntax in green (the Clojure data structure produced by the Reader) and semantics in blue (how that data is understood by the Clojure runtime).
85 | ;; **
86 |
87 | ;; **
88 | ;;; Most literal Clojure forms evaluate to themselves, *except* symbols and lists. Symbols are used to refer to something else and when evaluated, return what they refer to. Lists (as in the diagram) are evaluated as invocation.
89 | ;;;
90 | ;;; In the diagram, (+ 3 4) is read as a list containing the symbol (+) and two numbers (3 and 4). The first element (where + is found) can be called "function position", that is, a place to find the thing to invoke. While functions are an obvious thing to invoke, there are also a few special operators known to the runtime, macros, and a handful of other invokable things.
91 | ;;;
92 | ;;; Considering the evaluation of the expression above:
93 | ;;; * 3 and 4 evaluate to themselves (longs)
94 | ;;; * `+` evaluates to a function that implements +
95 | ;;; * evaluating the list will invoke the + function with 3 and 4 as arguments
96 | ;;;
97 | ;;; Many languages have both statements and expressions, where statements have some stateful effect but do not return a value. In Clojure, everything is an expression that evaluates to a value. Some expressions (but not most) also have side effects.
98 | ;; **
99 |
100 | ;; **
101 | ;;;
102 | ;; **
103 |
104 | ;; **
105 | ;;;
106 | ;; **
107 |
108 | ;; **
109 | ;;; Now let's consider how we can interactively evaluate expressions in Clojure.
110 | ;; **
111 |
112 | ;; **
113 | ;;; ### Delaying evaluation with quoting
114 | ;; **
115 |
116 | ;; **
117 | ;;; Sometimes it's useful to avoid the evaluation rules, in particular for symbols and lists. Sometimes a symbol should just be a symbol without looking up what it refers to:
118 | ;; **
119 |
120 | ;; @@
121 | 'x
122 | ;; @@
123 | ;; =>
124 | ;;; {"type":"html","content":"x","value":"x"}
125 | ;; <=
126 |
127 | ;; **
128 | ;;; And sometimes a list should just be a list of data values (not code to evaluate):
129 | ;; **
130 |
131 | ;; @@
132 | '(1 2 3)
133 | ;; @@
134 | ;; =>
135 | ;;; {"type":"list-like","open":"(","close":")","separator":" ","items":[{"type":"html","content":"1","value":"1"},{"type":"html","content":"2","value":"2"},{"type":"html","content":"3","value":"3"}],"value":"(1 2 3)"}
136 | ;; <=
137 |
138 | ;; **
139 | ;;;
140 | ;; **
141 |
142 | ;; **
143 | ;;; One confusing error you might see is the result of accidentally trying to evaluate a list of data as if it were code:
144 | ;; **
145 |
146 | ;; @@
147 | (1 2 3)
148 | ;; @@
149 |
150 | ;; **
151 | ;;; The `'` is a symbol syntax understood by the reader but it is equivalent to the special form `quote`:
152 | ;; **
153 |
154 | ;; @@
155 | (quote (1 2 3))
156 | ;; @@
157 | ;; =>
158 | ;;; {"type":"list-like","open":"(","close":")","separator":" ","items":[{"type":"html","content":"1","value":"1"},{"type":"html","content":"2","value":"2"},{"type":"html","content":"3","value":"3"}],"value":"(1 2 3)"}
159 | ;; <=
160 |
161 | ;; **
162 | ;;; For now, don't worry too much about quote but you will see it occasionally in these materials to avoid evaluation of symbols or lists.
163 | ;; **
164 |
165 | ;; **
166 | ;;; ## REPL
167 | ;;;
168 | ;;; Most of the time when you are using Clojure, you will do so in an editor or a REPL (Read-Eval-Print-Loop). The REPL has the following parts:
169 | ;;;
170 | ;;; 1. Read an expression (a string of characters) to produce Clojure data.
171 | ;;; 2. Evaluate the data returned from #1 to yield a result (also Clojure data).
172 | ;;; 3. Print the result by converting it from data back to characters.
173 | ;;; 4. Loop back to the beginning.
174 | ;;;
175 | ;;; One important aspect of #2 is that Clojure always compiles the expression before executing it; Clojure is **always** compiled to JVM bytecode. There is no Clojure interpreter.
176 | ;; **
177 |
178 | ;; @@
179 | (+ 3 4)
180 | ;; @@
181 | ;; =>
182 | ;;; {"type":"html","content":"7","value":"7"}
183 | ;; <=
184 |
185 | ;; **
186 | ;;; The box above demonstrates evaluating an expression (+ 3 4) and receiving a result. In this workshop, you will evaluate expressions directly in this web page. Each expression is editable and can be evaluated by pressing Shift-Enter.
187 | ;;;
188 | ;;; This web page is providing a bunch of web goo between your browser and the Clojure runtime, but otherwise is operating just like any other Clojure REPL.
189 | ;; **
190 |
191 | ;; **
192 | ;;; ### Exploring at the REPL
193 | ;;;
194 | ;;; Most REPL environments support a few tricks to help with interactive use. For example, some special symbols remember the results of evaluating the last three expressions:
195 | ;;;
196 | ;;; * `*1` (the last result)
197 | ;;; * `*2` (the result two expressions ago)
198 | ;;; * `*3` (the result three expressions ago)
199 | ;; **
200 |
201 | ;; @@
202 | (+ 3 4)
203 | (+ 10 *1) ;; *1 = 7
204 | (+ *1 *2) ;; *1 = 17, *2 = 7
205 | ;; @@
206 | ;; =>
207 | ;;; {"type":"html","content":"24","value":"24"}
208 | ;; <=
209 |
210 | ;; **
211 | ;;; In addition, there is a namespace `clojure.repl` that is included in the standard Clojure library that provides a number of helpful functions. To load that library and make it's functions available in our current context, call:
212 | ;; **
213 |
214 | ;; @@
215 | (require '[clojure.repl :refer :all])
216 | ;; @@
217 |
218 | ;; **
219 | ;;; For now, you can treat that as a magic incantation. Poof! We'll unpack it when we get to namespaces.
220 | ;;;
221 | ;;; We now have access to some additional functions that are useful at the REPL: `doc`, `find-doc`, `apropos`, `source`, and `dir`.
222 | ;;;
223 | ;;; The `doc` function displays the documentation for any function. Let's call it on `+`:
224 | ;; **
225 |
226 | ;; @@
227 | (doc +)
228 | ;; @@
229 | ;; ->
230 | ;;; -------------------------
231 | ;;; clojure.core/+
232 | ;;; ([] [x] [x y] [x y & more])
233 | ;;; Returns the sum of nums. (+) returns 0. Does not auto-promote
234 | ;;; longs, will throw on overflow. See also: +'
235 | ;;;
236 | ;; <-
237 | ;; =>
238 | ;;; {"type":"html","content":"nil","value":"nil"}
239 | ;; <=
240 |
241 | ;; **
242 | ;;; The `doc` function prints the documentation for `+`, including the valid signatures.
243 | ;;;
244 | ;;; The doc function prints the documentation, then returns nil as the result - you will see both in the evaluation output.
245 | ;;;
246 | ;;; We can invoke `doc` on itself too:
247 | ;; **
248 |
249 | ;; @@
250 | (doc doc)
251 | ;; @@
252 | ;; ->
253 | ;;; -------------------------
254 | ;;; clojure.repl/doc
255 | ;;; ([name])
256 | ;;; Macro
257 | ;;; Prints documentation for a var or special form given its name
258 | ;;;
259 | ;; <-
260 | ;; =>
261 | ;;; {"type":"html","content":"nil","value":"nil"}
262 | ;; <=
263 |
264 | ;; **
265 | ;;; Not sure what something is called? You can use the `apropos` command to find functions that match a particular string or regular expression.
266 | ;; **
267 |
268 | ;; @@
269 | (apropos "+")
270 | ;; @@
271 | ;; =>
272 | ;;; {"type":"list-like","open":"(","close":")","separator":" ","items":[{"type":"html","content":"clojure.core/+","value":"clojure.core/+"},{"type":"html","content":"clojure.core/+'","value":"clojure.core/+'"}],"value":"(clojure.core/+ clojure.core/+')"}
273 | ;; <=
274 |
275 | ;; **
276 | ;;; You can also widen your search to include the docstrings themselves with `find-doc`:
277 | ;; **
278 |
279 | ;; @@
280 | (find-doc "trim")
281 | ;; @@
282 | ;; ->
283 | ;;; -------------------------
284 | ;;; clojure.core/subvec
285 | ;;; ([v start] [v start end])
286 | ;;; Returns a persistent vector of the items in vector from
287 | ;;; start (inclusive) to end (exclusive). If end is not supplied,
288 | ;;; defaults to (count vector). This operation is O(1) and very fast, as
289 | ;;; the resulting vector shares structure with the original and no
290 | ;;; trimming is done.
291 | ;;; -------------------------
292 | ;;; clojure.string/trim
293 | ;;; ([s])
294 | ;;; Removes whitespace from both ends of string.
295 | ;;; -------------------------
296 | ;;; clojure.string/trim-newline
297 | ;;; ([s])
298 | ;;; Removes all trailing newline \n or return \r characters from
299 | ;;; string. Similar to Perl's chomp.
300 | ;;; -------------------------
301 | ;;; clojure.string/triml
302 | ;;; ([s])
303 | ;;; Removes whitespace from the left side of string.
304 | ;;; -------------------------
305 | ;;; clojure.string/trimr
306 | ;;; ([s])
307 | ;;; Removes whitespace from the right side of string.
308 | ;;;
309 | ;; <-
310 | ;; =>
311 | ;;; {"type":"html","content":"nil","value":"nil"}
312 | ;; <=
313 |
314 | ;; **
315 | ;;; If you'd like to see a full listing of the functions in a particular namespace, you can use the `dir` function. Here we can use it on the `clojure.repl` namespace:
316 | ;; **
317 |
318 | ;; @@
319 | (dir clojure.repl)
320 | ;; @@
321 | ;; ->
322 | ;;; apropos
323 | ;;; demunge
324 | ;;; dir
325 | ;;; dir-fn
326 | ;;; doc
327 | ;;; find-doc
328 | ;;; pst
329 | ;;; root-cause
330 | ;;; set-break-handler!
331 | ;;; source
332 | ;;; source-fn
333 | ;;; stack-element-str
334 | ;;; thread-stopper
335 | ;;;
336 | ;; <-
337 | ;; =>
338 | ;;; {"type":"html","content":"nil","value":"nil"}
339 | ;; <=
340 |
341 | ;; **
342 | ;;; And finally, we can see not only the documentation but the underlying source for any function accessible by the runtime:
343 | ;; **
344 |
345 | ;; @@
346 | (source dir)
347 | ;; @@
348 | ;; ->
349 | ;;; (defmacro dir
350 | ;;; "Prints a sorted directory of public vars in a namespace"
351 | ;;; [nsname]
352 | ;;; `(doseq [v# (dir-fn '~nsname)]
353 | ;;; (println v#)))
354 | ;;;
355 | ;; <-
356 | ;; =>
357 | ;;; {"type":"html","content":"nil","value":"nil"}
358 | ;; <=
359 |
360 | ;; **
361 | ;;; As you go through this workshop, please feel free to examine the docstring and source for the functions you are using. Exploring the implementation of the Clojure library itself is an excellent way to learn more about the language and how it is used.
362 | ;;;
363 | ;;; It is also an excellent idea to keep a copy of the [Clojure Cheatsheet](http://clojure.org/cheatsheet) open while you are learning Clojure. The cheatsheet categorizes the functions available in the standard library and is an invaluable reference.
364 | ;;;
365 | ;;; Now let's consider some Clojure basics to get you going....
366 | ;; **
367 |
368 | ;; **
369 | ;;; ## Clojure basics
370 | ;;;
371 | ;;; ### def
372 | ;;;
373 | ;;; When you are evaluating things at a REPL, it can be useful to save a piece of data for later. We can do this with `def`:
374 | ;; **
375 |
376 | ;; @@
377 | (def x 7)
378 | ;; @@
379 | ;; =>
380 | ;;; {"type":"html","content":"#'user/x","value":"#'user/x"}
381 | ;; <=
382 |
383 | ;; **
384 | ;;; `def` is a special form that associates a symbol (x) in the current namespace with a value (7). This linkage is called a `var`. In most actual Clojure code, vars should refer to either a constant value or a function, but it's common to define and re-define them for convenience when working at the REPL.
385 | ;;;
386 | ;;; Note the return value above is `#'user/x` - that's the literal representation for a var: `#'` followed by the namespaced symbol. `user` is the default namespace.
387 | ;;;
388 | ;;; Recall that symbols are evaluated by looking up what they refer to, so we can get the value back by just using the symbol:
389 | ;; **
390 |
391 | ;; @@
392 | (+ x x)
393 | ;; @@
394 | ;; =>
395 | ;;; {"type":"html","content":"14","value":"14"}
396 | ;; <=
397 |
398 | ;; **
399 | ;;; ### Printing
400 | ;; **
401 |
402 | ;; **
403 | ;;; One of the most common things you do when learning a language is to print out values. Clojure provides several functions for printing values:
404 | ;;;
405 | ;;; | | Human-Readable | Machine-Readable |
406 | ;;; |-|----------------|------------------|
407 | ;;; |With newline| println | prn |
408 | ;;; |Without newline | print | pr |
409 | ;;;
410 | ;;; The human-readable forms will translate special print characters (like newlines and tabs) to their expected form and print strings without quotes. We often use `println` to debug functions or print a value at the REPL. `println` takes any number of arguments and interposes a space between each argument's printed value:
411 | ;; **
412 |
413 | ;; @@
414 | (println "What is this:" (+ 1 2))
415 | ;; @@
416 | ;; ->
417 | ;;; What is this: 3
418 | ;;;
419 | ;; <-
420 | ;; =>
421 | ;;; {"type":"html","content":"nil","value":"nil"}
422 | ;; <=
423 |
424 | ;; **
425 | ;;; The `println` function has side-effects (printing) and returns nil as a result.
426 | ;;;
427 | ;;; Note that `"What is this:"` above did not print the surrouding quotes and is not a string that the Reader could read again in the same way. For that purpose, use the machine-readable version `prn`:
428 | ;; **
429 |
430 | ;; @@
431 | (prn "one\n\ttwo")
432 | ;; @@
433 | ;; ->
434 | ;;; "one\n\ttwo"
435 | ;;;
436 | ;; <-
437 | ;; =>
438 | ;;; {"type":"html","content":"nil","value":"nil"}
439 | ;; <=
440 |
441 | ;; **
442 | ;;; Note that the printed result is a valid form that the Reader could read again. Both human- and readable- printing functions are useful in different contexts.
443 | ;; **
444 |
445 | ;; **
446 | ;;; ## LAB
447 | ;; **
448 |
449 | ;; **
450 | ;;;
451 | ;; **
452 |
453 | ;; **
454 | ;;; Using the REPL, compute the sum of 7654 and 1234.
455 | ;;;
456 | ;; **
457 |
458 | ;; @@
459 |
460 | ;; expected result = 8888
461 | ;; @@
462 |
463 | ;; **
464 | ;;; Rewrite the following algebraic expression as a Clojure expression.
465 | ;; **
466 |
467 | ;; @@
468 |
469 | ;; expected result = 12/5
470 | ;; @@
471 |
472 | ;; **
473 | ;;; Using REPL documentation functions, find the documentation for the `rem` and `mod` functions. Compare the results of the provided expressions based on the documentation.
474 | ;; **
475 |
476 | ;; @@
477 | ;; make all functions in the clojure.repl namespace
478 | (require '[clojure.repl :refer :all])
479 |
480 | (rem 10 -8)
481 | (mod 10 -8)
482 |
483 | ;; @@
484 |
485 | ;; **
486 | ;;; Using `find-doc`, find the function that prints the stack trace of the most recent REPL exception.
487 | ;; **
488 |
489 | ;; @@
490 | ;; You can provoke an exception like this:
491 | (throw (Exception. "oh no!"))
492 | ;; @@
493 |
494 | ;; **
495 | ;;;
496 | ;;; ## Navigation
497 | ;;;
498 | ;;; * [Up (Home)](/worksheet.html?filename=src/cljlab/start.clj)
499 | ;;; * [Previous (Home)](/worksheet.html?filename=src/cljlab/start.clj)
500 | ;;; * [Next (Functions)](/worksheet.html?filename=src/cljlab/functions.clj)
501 | ;;;
502 | ;; **
503 |
--------------------------------------------------------------------------------
/src/start.clj:
--------------------------------------------------------------------------------
1 | (ns start
2 | (:require gorilla-repl.core)
3 | (:gen-class))
4 |
5 | (defn -main [& args]
6 | (let [port (Long/parseLong (or (first args) "55555"))]
7 | (gorilla-repl.core/run-gorilla-server {:port port})
8 | (println (str "Load: http://127.0.0.1:" port "/worksheet.html?filename=src/cljlab/start.clj"))))
--------------------------------------------------------------------------------