├── .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 | Creative Commons License
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 | 19 | 21 | 23 | 27 | 31 | 32 | 34 | 38 | 42 | 43 | 45 | 49 | 53 | 54 | 56 | 60 | 64 | 65 | 72 | 78 | 79 | 86 | 92 | 93 | 100 | 106 | 107 | 114 | 116 | 120 | 124 | 125 | 127 | 131 | 135 | 136 | 145 | 155 | 165 | 175 | 185 | 192 | 193 | 216 | 218 | 219 | 221 | image/svg+xml 222 | 224 | 225 | 226 | 227 | 228 | 233 | x fi 268 | 281 | 292 | 299 | 306 | 313 | seq 324 | 330 | 336 | 342 | r 353 | 1 364 | a 375 | 381 | 382 | 383 | -------------------------------------------------------------------------------- /images/collections-seq-lazy-initial.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 23 | 27 | 31 | 32 | 34 | 38 | 42 | 43 | 45 | 49 | 53 | 54 | 56 | 60 | 64 | 65 | 72 | 78 | 79 | 86 | 92 | 93 | 100 | 106 | 107 | 114 | 116 | 120 | 124 | 125 | 127 | 131 | 135 | 136 | 145 | 155 | 165 | 175 | 185 | 192 | 193 | 216 | 218 | 219 | 221 | image/svg+xml 222 | 224 | 225 | 226 | 227 | 228 | 233 | x fi 268 | 281 | 292 | 299 | 306 | 313 | seq 324 | 330 | 336 | 342 | r 353 | 354 | 355 | -------------------------------------------------------------------------------- /images/collections-seq-lazy-rest.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 23 | 27 | 31 | 32 | 34 | 38 | 42 | 43 | 45 | 49 | 53 | 54 | 56 | 60 | 64 | 65 | 72 | 78 | 79 | 86 | 92 | 93 | 100 | 106 | 107 | 114 | 116 | 120 | 124 | 125 | 127 | 131 | 135 | 136 | 145 | 155 | 165 | 175 | 185 | 192 | 193 | 216 | 218 | 219 | 221 | image/svg+xml 222 | 224 | 225 | 226 | 227 | 228 | 233 | x fi 268 | 281 | 292 | 299 | 306 | 313 | seq 324 | 330 | 336 | 342 | s 353 | 1 364 | 371 | 378 | 385 | seq 396 | 402 | 408 | 409 | 410 | -------------------------------------------------------------------------------- /images/collections-seq-lazy-second.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 23 | 27 | 31 | 32 | 34 | 38 | 42 | 43 | 45 | 49 | 53 | 54 | 56 | 60 | 64 | 65 | 72 | 78 | 79 | 86 | 92 | 93 | 100 | 106 | 107 | 114 | 116 | 120 | 124 | 125 | 127 | 131 | 135 | 136 | 145 | 155 | 165 | 175 | 185 | 192 | 193 | 216 | 218 | 219 | 221 | image/svg+xml 222 | 224 | 225 | 226 | 227 | 228 | 233 | x fi 268 | 281 | 292 | 299 | 306 | 313 | seq 324 | 330 | 336 | 1 347 | 354 | 361 | 368 | seq 379 | 385 | 391 | 2 402 | b 413 | 419 | 420 | 421 | -------------------------------------------------------------------------------- /images/collections-seq-list-initial.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 23 | 27 | 31 | 32 | 34 | 38 | 42 | 43 | 45 | 49 | 53 | 54 | 56 | 60 | 64 | 65 | 72 | 78 | 79 | 86 | 92 | 93 | 100 | 106 | 107 | 114 | 116 | 120 | 124 | 125 | 127 | 131 | 135 | 136 | 145 | 155 | 165 | 175 | 185 | 192 | 193 | 216 | 218 | 219 | 221 | image/svg+xml 222 | 224 | 225 | 226 | 227 | 228 | 233 | 239 | x fi 274 | 287 | 294 | 301 | 307 | 1 319 | 325 | 332 | 339 | 345 | 2 357 | 363 | 370 | 377 | 383 | 3 395 | 401 | x 412 | 413 | 414 | -------------------------------------------------------------------------------- /images/collections-seq-list-rest.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 23 | 27 | 31 | 32 | 34 | 38 | 42 | 43 | 45 | 49 | 53 | 54 | 56 | 60 | 64 | 65 | 72 | 78 | 79 | 86 | 92 | 93 | 100 | 106 | 107 | 114 | 116 | 120 | 124 | 125 | 127 | 131 | 135 | 136 | 145 | 155 | 165 | 175 | 185 | 192 | 193 | 216 | 218 | 219 | 221 | image/svg+xml 222 | 224 | 225 | 226 | 227 | 228 | 233 | 239 | x fi 274 | 287 | 294 | 301 | 307 | 1 319 | 325 | 332 | 339 | 345 | 2 357 | 363 | 370 | 377 | 383 | 3 395 | 401 | x 412 | 423 | 429 | s 440 | 441 | 442 | -------------------------------------------------------------------------------- /images/collections-seq-vector-first.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 23 | 27 | 31 | 32 | 34 | 38 | 42 | 43 | 45 | 49 | 53 | 54 | 56 | 60 | 64 | 65 | 72 | 78 | 79 | 86 | 92 | 93 | 100 | 106 | 107 | 114 | 116 | 120 | 124 | 125 | 127 | 131 | 135 | 136 | 145 | 155 | 165 | 175 | 185 | 192 | 193 | 216 | 218 | 219 | 221 | image/svg+xml 222 | 224 | 225 | 226 | 227 | 228 | 233 | x fi 268 | 281 | 288 | 295 | 301 | 307 | 318 | 325 | 332 | 2 344 | 351 | 1 363 | 3 375 | 382 | seq 393 | 399 | a 410 | 411 | 412 | -------------------------------------------------------------------------------- /images/collections-seq-vector-initial.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 23 | 27 | 31 | 32 | 34 | 38 | 42 | 43 | 45 | 49 | 53 | 54 | 56 | 60 | 64 | 65 | 72 | 78 | 79 | 86 | 92 | 93 | 100 | 106 | 107 | 114 | 116 | 120 | 124 | 125 | 127 | 131 | 135 | 136 | 145 | 155 | 165 | 175 | 185 | 192 | 193 | 216 | 218 | 219 | 221 | image/svg+xml 222 | 224 | 225 | 226 | 227 | 228 | 233 | x fi 268 | 281 | 292 | 299 | 306 | 2 318 | 325 | 1 337 | 3 349 | 355 | v 366 | 367 | 368 | -------------------------------------------------------------------------------- /images/collections-seq-vector-seq.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 23 | 27 | 31 | 32 | 34 | 38 | 42 | 43 | 45 | 49 | 53 | 54 | 56 | 60 | 64 | 65 | 72 | 78 | 79 | 86 | 92 | 93 | 100 | 106 | 107 | 114 | 116 | 120 | 124 | 125 | 127 | 131 | 135 | 136 | 145 | 155 | 165 | 175 | 185 | 192 | 193 | 216 | 218 | 219 | 221 | image/svg+xml 222 | 224 | 225 | 226 | 227 | 228 | 233 | 239 | x fi 274 | 287 | 294 | 301 | 307 | 313 | s1 324 | 335 | 342 | 349 | 2 361 | 368 | 1 380 | 3 392 | 398 | v 409 | 416 | seq 427 | 428 | 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 | ;;; ![Namespace concepts](project-files/images/namespaces-total.svg) 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 | ;;; 322 | ;;; 323 | ;;; 324 | ;;; 325 | ;;; 326 | ;;; 327 | ;;; 328 | ;;; 329 | ;;; 330 | ;;; 331 | ;;; 332 | ;;; 333 | ;;; 334 | ;;; 335 | ;;; 336 | ;;; 337 | ;;; 338 | ;;; 339 | ;;; 340 | ;;; 341 | ;;; 342 | ;;; 343 | ;;; 344 | ;;; 345 | ;;; 346 | ;;; 347 | ;;; 348 | ;;;
FunctionReturns map of symbols to...
`ns-map`all vars and classes
-> `ns-interns`all vars created in this namespace
-> -> `ns-publics`all *public* vars in this namespace
-> `ns-refers`*referred* vars from other namespaces
-> `ns-imports`Java classes
`ns-aliases`aliased namespaces
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 | ;;; ![Structure vs semantics](project-files/images/state1.png) 42 | ;;; 43 | ;;; ![Structure vs semantics](project-files/images/state2.png) 44 | ;;; 45 | ;;; ![Structure vs semantics](project-files/images/state3.png) 46 | ;;; 47 | ;;; ![Structure vs semantics](project-files/images/state4.png) 48 | ;;; 49 | ;;; ![Structure vs semantics](project-files/images/state5.png) 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 | ;;; ![Traditional evaluation](project-files/images/traditional-evaluation.png) 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 | ;;; ![Clojure evaluation](project-files/images/clojure-evaluation.png) 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 | ;;; ![Structure vs semantics](project-files/images/structure-and-semantics.png) 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")))) --------------------------------------------------------------------------------