├── .gitignore
├── .clj-kondo
└── .cache
│ └── v1
│ ├── lock
│ └── clj
│ ├── examples.data.planets.transit.json
│ ├── echo-server.handler-test.transit.json
│ ├── echo-server.handler.transit.json
│ ├── examples.ex00-introduction.transit.json
│ ├── clojure-by-example.ex00-introduction.transit.json
│ ├── examples.fun.workshop-fmt.transit.json
│ ├── examples.ex05-immutability-and-fp.transit.json
│ ├── examples.ex06-full-functional-firepower.transit.json
│ ├── examples.ex01-fundamentally-functional.transit.json
│ ├── examples.ex02-domain-as-data.transit.json
│ ├── clojure-by-example.ex02-domain-as-data.transit.json
│ ├── examples.fun.inspect-nasa-planets.transit.json
│ ├── examples.ex04-api-design.transit.json
│ └── examples.ex03-data-and-functions.transit.json
├── tutorials
└── clojure-by-example
│ ├── .clj-kondo
│ └── .cache
│ │ └── v1
│ │ ├── lock
│ │ └── clj
│ │ ├── examples.ex00-introduction.transit.json
│ │ ├── clojure-by-example.ex00-introduction.transit.json
│ │ ├── clojure-by-example.ex06-full-functional-firepower.transit.json
│ │ ├── examples.ex01-fundamentally-functional.transit.json
│ │ ├── clojure-by-example.ex01-fundamentally-functional.transit.json
│ │ ├── examples.ex02-domain-as-data.transit.json
│ │ └── clojure-by-example.ex02-domain-as-data.transit.json
│ ├── src
│ └── examples
│ │ ├── workshop
│ │ ├── .gitignore
│ │ └── README.txt
│ │ ├── ex08_but_before_we_go.clj
│ │ ├── data
│ │ └── planets.clj
│ │ ├── fun
│ │ ├── workshop_fmt.clj
│ │ └── inspect_nasa_planets.clj
│ │ ├── ex02_domain_as_data.clj
│ │ ├── ex07_boldly_go.clj
│ │ ├── ex00_introduction.clj
│ │ ├── ex05_immutability_and_fp.clj
│ │ ├── ex06_full_functional_firepower.clj
│ │ ├── ex04_api_design.clj
│ │ ├── ex01_fundamentally_functional.clj
│ │ └── ex03_data_and_functions.clj
│ ├── resources
│ └── sensor_data
│ │ ├── moon_detector.json
│ │ ├── planet_detector.json
│ │ ├── atmospheric_detector.json
│ │ └── consolidated_data.json
│ ├── doc
│ └── intro.md
│ ├── .gitignore
│ ├── project.clj
│ ├── CHANGELOG.md
│ ├── LICENSE
│ └── README.md
├── web
└── echo-server
│ ├── .gitignore
│ ├── .idea
│ ├── .gitignore
│ ├── ClojureProjectResolveSettings.xml
│ ├── modules.xml
│ ├── libraries
│ │ ├── Leiningen__clout_2_2_1.xml
│ │ ├── Leiningen__nrepl_1_0_0.xml
│ │ ├── Leiningen__hiccup_1_0_5.xml
│ │ ├── Leiningen__medley_1_0_0.xml
│ │ ├── Leiningen__tigris_0_1_1.xml
│ │ ├── Leiningen__cheshire_5_8_0.xml
│ │ ├── Leiningen__clj_time_0_11_0.xml
│ │ ├── Leiningen__commons_io_2_5.xml
│ │ ├── Leiningen__compojure_1_6_1.xml
│ │ ├── Leiningen__joda_time_2_8_2.xml
│ │ ├── Leiningen__ring_ring_ssl_0_3_0.xml
│ │ ├── Leiningen__instaparse_1_4_8.xml
│ │ ├── Leiningen__ring_ring_core_1_6_3.xml
│ │ ├── Leiningen__ring_ring_mock_0_3_2.xml
│ │ ├── Leiningen__ring_ring_codec_1_1_0.xml
│ │ ├── Leiningen__commons_codec_1_10.xml
│ │ ├── Leiningen__crypto_random_1_2_0.xml
│ │ ├── Leiningen__ring_ring_defaults_0_3_2.xml
│ │ ├── Leiningen__ring_ring_headers_0_3_0.xml
│ │ ├── Leiningen__org_clojure_clojure_1_10_0.xml
│ │ ├── Leiningen__org_nrepl_incomplete_0_1_0.xml
│ │ ├── Leiningen__crypto_equality_1_0_0.xml
│ │ ├── Leiningen__javax_servlet_servlet_api_2_5.xml
│ │ ├── Leiningen__org_clojure_tools_macro_0_1_5.xml
│ │ ├── Leiningen__org_clojure_spec_alpha_0_2_176.xml
│ │ ├── Leiningen__ring_ring_anti_forgery_1_3_0.xml
│ │ ├── Leiningen__commons_fileupload_1_3_3.xml
│ │ ├── Leiningen__org_clojure_core_specs_alpha_0_2_44.xml
│ │ ├── Leiningen__javax_servlet_javax_servlet_api_3_1_0.xml
│ │ ├── Leiningen__com_fasterxml_jackson_core_jackson_core_2_9_0.xml
│ │ ├── Leiningen__com_fasterxml_jackson_dataformat_jackson_dataformat_cbor_2_9_0.xml
│ │ └── Leiningen__com_fasterxml_jackson_dataformat_jackson_dataformat_smile_2_9_0.xml
│ ├── misc.xml
│ ├── aws.xml
│ ├── compiler.xml
│ ├── inspectionProfiles
│ │ └── Project_Default.xml
│ └── dbnavigator.xml
│ ├── README.md
│ ├── src
│ └── echo_server
│ │ └── handler.clj
│ ├── project.clj
│ ├── test
│ └── echo_server
│ │ └── handler_test.clj
│ └── echo-server.iml
├── .lsp
└── .cache
│ └── db.transit.json
├── LICENSE
├── README.md
├── index.html
└── header.svg
/.gitignore:
--------------------------------------------------------------------------------
1 | .calva
2 |
--------------------------------------------------------------------------------
/.clj-kondo/.cache/v1/lock:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tutorials/clojure-by-example/.clj-kondo/.cache/v1/lock:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tutorials/clojure-by-example/src/examples/workshop/.gitignore:
--------------------------------------------------------------------------------
1 | *.clj
2 |
--------------------------------------------------------------------------------
/tutorials/clojure-by-example/resources/sensor_data/moon_detector.json:
--------------------------------------------------------------------------------
1 | {"Mercury":0,"Venus":0,"Earth":1,"Mars":2,"Chlorine Planet":4,"Insane Planet":42}
--------------------------------------------------------------------------------
/tutorials/clojure-by-example/doc/intro.md:
--------------------------------------------------------------------------------
1 | # Introduction to Clojure By Example
2 |
3 | All that needed to be said has been said in the README.md file.
4 |
--------------------------------------------------------------------------------
/web/echo-server/.gitignore:
--------------------------------------------------------------------------------
1 | /target
2 | /lib
3 | /classes
4 | /checkouts
5 | pom.xml
6 | pom.xml.asc
7 | *.jar
8 | *.class
9 | /.lein-*
10 | /.nrepl-port
11 |
--------------------------------------------------------------------------------
/web/echo-server/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Editor-based HTTP Client requests
5 | /httpRequests/
6 | # Datasource local storage ignored files
7 | /dataSources/
8 | /dataSources.local.xml
9 |
--------------------------------------------------------------------------------
/web/echo-server/.idea/ClojureProjectResolveSettings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | IDE
5 |
6 |
--------------------------------------------------------------------------------
/tutorials/clojure-by-example/.gitignore:
--------------------------------------------------------------------------------
1 | /target
2 | /classes
3 | /checkouts
4 | pom.xml
5 | pom.xml.asc
6 | *.jar
7 | *.class
8 | /.lein-*
9 | /.nrepl-port
10 | .hgignore
11 | .hg/
12 | .setup.sh
13 | profiles.clj
14 | .idea
15 | .m2-for-inclojure
16 | *.iml
17 |
--------------------------------------------------------------------------------
/tutorials/clojure-by-example/resources/sensor_data/planet_detector.json:
--------------------------------------------------------------------------------
1 | {"Mercury":{"mass":0.055,"radius":0.383},"Venus":{"mass":0.815,"radius":0.949},"Earth":{"mass":1,"radius":1},"Mars":{"mass":0.107,"radius":0.532},"Chlorine Planet":{"mass":2.5,"radius":1.3},"Insane Planet":{"mass":4.2,"radius":1.42}}
--------------------------------------------------------------------------------
/web/echo-server/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/web/echo-server/.idea/libraries/Leiningen__clout_2_2_1.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/web/echo-server/.idea/libraries/Leiningen__nrepl_1_0_0.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.clj-kondo/.cache/v1/clj/examples.data.planets.transit.json:
--------------------------------------------------------------------------------
1 | ["^ ","~$target-planets",["^ ","~:row",3,"~:col",1,"~:name","^0","~:ns","~$examples.data.planets","~:top-ns","^5","~:type","~:vector"],"~:filename","/Users/zhangzixiong/Desktop/Workspace/Github/examples/clojure-examples/snippets/clojure-by-example/src/examples/data/planets.clj"]
--------------------------------------------------------------------------------
/web/echo-server/.idea/libraries/Leiningen__hiccup_1_0_5.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/web/echo-server/.idea/libraries/Leiningen__medley_1_0_0.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/web/echo-server/.idea/libraries/Leiningen__tigris_0_1_1.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.clj-kondo/.cache/v1/clj/echo-server.handler-test.transit.json:
--------------------------------------------------------------------------------
1 | ["^ ","~$test-app",["^ ","~:row",6,"~:col",1,"~:fixed-arities",["~#set",[0]],"~:name","^0","~:ns","~$echo-server.handler-test","~:top-ns","^7"],"~:filename","/Users/zhangzixiong/Desktop/Workspace/Github/examples/clojure-examples/web/echo-server/test/echo_server/handler_test.clj"]
--------------------------------------------------------------------------------
/tutorials/clojure-by-example/src/examples/workshop/README.txt:
--------------------------------------------------------------------------------
1 | DO NOT commit clj files here.
2 |
3 | This directory is a target for generated clj source files.
4 |
5 | A reformatter will read "full featured" source meant for at-home use,
6 | and dump an elided, leaner version here for in-class use (for the
7 | teacher's convenience).
8 |
--------------------------------------------------------------------------------
/web/echo-server/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/web/echo-server/.idea/libraries/Leiningen__cheshire_5_8_0.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/web/echo-server/.idea/libraries/Leiningen__clj_time_0_11_0.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/web/echo-server/.idea/libraries/Leiningen__commons_io_2_5.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/web/echo-server/.idea/libraries/Leiningen__compojure_1_6_1.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/web/echo-server/.idea/libraries/Leiningen__joda_time_2_8_2.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/web/echo-server/.idea/libraries/Leiningen__ring_ring_ssl_0_3_0.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.clj-kondo/.cache/v1/clj/echo-server.handler.transit.json:
--------------------------------------------------------------------------------
1 | ["^ ","~$app-routes",["^ ","~:row",6,"~:col",1,"~:name","^0","~:ns","~$echo-server.handler","~:top-ns","^5"],"~$app",["^ ","^1",10,"^2",1,"^3","^7","^4","^5","^6","^5"],"~:filename","/Users/zhangzixiong/Desktop/Workspace/Github/examples/clojure-examples/web/echo-server/src/echo_server/handler.clj"]
--------------------------------------------------------------------------------
/web/echo-server/.idea/libraries/Leiningen__instaparse_1_4_8.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/web/echo-server/.idea/libraries/Leiningen__ring_ring_core_1_6_3.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/web/echo-server/.idea/libraries/Leiningen__ring_ring_mock_0_3_2.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/web/echo-server/.idea/libraries/Leiningen__ring_ring_codec_1_1_0.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/web/echo-server/.idea/libraries/Leiningen__commons_codec_1_10.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/web/echo-server/.idea/libraries/Leiningen__crypto_random_1_2_0.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/web/echo-server/.idea/libraries/Leiningen__ring_ring_defaults_0_3_2.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/web/echo-server/.idea/libraries/Leiningen__ring_ring_headers_0_3_0.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/web/echo-server/.idea/aws.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/web/echo-server/.idea/libraries/Leiningen__org_clojure_clojure_1_10_0.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/web/echo-server/.idea/libraries/Leiningen__org_nrepl_incomplete_0_1_0.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/web/echo-server/.idea/libraries/Leiningen__crypto_equality_1_0_0.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/web/echo-server/.idea/libraries/Leiningen__javax_servlet_servlet_api_2_5.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/web/echo-server/.idea/libraries/Leiningen__org_clojure_tools_macro_0_1_5.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/web/echo-server/.idea/libraries/Leiningen__org_clojure_spec_alpha_0_2_176.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/web/echo-server/.idea/libraries/Leiningen__ring_ring_anti_forgery_1_3_0.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/web/echo-server/README.md:
--------------------------------------------------------------------------------
1 | # echo-server
2 |
3 | FIXME
4 |
5 | ## Prerequisites
6 |
7 | You will need [Leiningen][] 2.0.0 or above installed.
8 |
9 | [leiningen]: https://github.com/technomancy/leiningen
10 |
11 | ## Running
12 |
13 | To start a web server for the application, run:
14 |
15 | lein ring server
16 |
17 | ## License
18 |
19 | Copyright © 2023 FIXME
20 |
--------------------------------------------------------------------------------
/web/echo-server/.idea/libraries/Leiningen__commons_fileupload_1_3_3.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/web/echo-server/.idea/libraries/Leiningen__org_clojure_core_specs_alpha_0_2_44.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/web/echo-server/.idea/libraries/Leiningen__javax_servlet_javax_servlet_api_3_1_0.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/web/echo-server/src/echo_server/handler.clj:
--------------------------------------------------------------------------------
1 | (ns echo-server.handler
2 | (:require [compojure.core :refer :all]
3 | [compojure.route :as route]
4 | [ring.middleware.defaults :refer [wrap-defaults site-defaults]]))
5 |
6 | (defroutes app-routes
7 | (GET "/" [] "Hello World")
8 | (route/not-found "Not Found"))
9 |
10 | (def app
11 | (wrap-defaults app-routes site-defaults))
12 |
--------------------------------------------------------------------------------
/web/echo-server/.idea/libraries/Leiningen__com_fasterxml_jackson_core_jackson_core_2_9_0.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.lsp/.cache/db.transit.json:
--------------------------------------------------------------------------------
1 | ["^ ","~:classpath",["~#set",[]],"~:project-hash","","~:project-root","/Users/zhangzixiong/Desktop/Workspace/Github/examples/clojure-examples","~:kondo-config-hash","9adc30dd64a9430408738b7cfcf1bc22fa641d07e88c63d7e1fe8a6d7f91d654","~:dependency-scheme","jar","~:analysis",null,"~:analysis-checksums",["^ "],"~:project-analysis-type","~:project-and-dependencies","~:version",8,"~:stubs-generation-namespaces",["^1",[]]]
--------------------------------------------------------------------------------
/web/echo-server/.idea/libraries/Leiningen__com_fasterxml_jackson_dataformat_jackson_dataformat_cbor_2_9_0.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/web/echo-server/.idea/libraries/Leiningen__com_fasterxml_jackson_dataformat_jackson_dataformat_smile_2_9_0.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/tutorials/clojure-by-example/resources/sensor_data/atmospheric_detector.json:
--------------------------------------------------------------------------------
1 | {"Mercury":{},"Venus":{"carbon-dioxide":96.45,"nitrogen":3.45,"sulphur-dioxide":0.015,"traces":0.095},"Earth":{"nitrogen":78.08,"oxygen":20.95,"carbon-dioxide":0.4,"water-vapour":0.1,"argon":0.33,"traces":0.14},"Mars":{"carbon-dioxide":95.97,"argon":1.93,"nitrogen":1.89,"oxygen":0.146,"carbon-monoxide":0.056,"traces":0.008},"Chlorine Planet":{"chlorine":100.0},"Insane Planet":{"sulphur-dioxide":80.0,"carbon-monoxide":10.0,"chlorine":5.0,"nitrogen":5.0}}
--------------------------------------------------------------------------------
/.clj-kondo/.cache/v1/clj/examples.ex00-introduction.transit.json:
--------------------------------------------------------------------------------
1 | ["^ ","~$same",["^ ","~:row",57,"~:col",1,"~:fixed-arities",["~#set",[1]],"~:name","^0","~:ns","~$examples.ex00-introduction","~:top-ns","^7","~:type","~:fn"],"~$hie",["^ ","^1",215,"^2",1,"^3",["^4",[2]],"^5","^;","^6","^7","^8","^7","~:arities",["^ ","~i2",["^ ","~:ret","~:string","~:arglist-str","[person message]"]],"^9","^:"],"~:filename","/Users/zhangzixiong/Desktop/Workspace/Github/examples/clojure-examples/snippets/clojure-by-example/src/examples/ex00_introduction.clj"]
--------------------------------------------------------------------------------
/web/echo-server/project.clj:
--------------------------------------------------------------------------------
1 | (defproject echo-server "0.1.0-SNAPSHOT"
2 | :description "FIXME: write description"
3 | :url "http://example.com/FIXME"
4 | :min-lein-version "2.0.0"
5 | :dependencies [[org.clojure/clojure "1.10.0"]
6 | [compojure "1.6.1"]
7 | [ring/ring-defaults "0.3.2"]]
8 | :plugins [[lein-ring "0.12.5"]]
9 | :ring {:handler echo-server.handler/app}
10 | :profiles
11 | {:dev {:dependencies [[javax.servlet/servlet-api "2.5"]
12 | [ring/ring-mock "0.3.2"]]}})
13 |
--------------------------------------------------------------------------------
/.clj-kondo/.cache/v1/clj/clojure-by-example.ex00-introduction.transit.json:
--------------------------------------------------------------------------------
1 | ["^ ","~$same",["^ ","~:row",57,"~:col",1,"~:fixed-arities",["~#set",[1]],"~:name","^0","~:ns","~$clojure-by-example.ex00-introduction","~:top-ns","^7","~:type","~:fn"],"~$hie",["^ ","^1",215,"^2",1,"^3",["^4",[2]],"^5","^;","^6","^7","^8","^7","~:arities",["^ ","~i2",["^ ","~:ret","~:string","~:arglist-str","[person message]"]],"^9","^:"],"~:filename","/Users/zhangzixiong/Desktop/Workspace/Github/examples/clojure-examples/snippets/clojure-by-example/src/clojure_by_example/ex00_introduction.clj"]
--------------------------------------------------------------------------------
/tutorials/clojure-by-example/.clj-kondo/.cache/v1/clj/examples.ex00-introduction.transit.json:
--------------------------------------------------------------------------------
1 | ["^ ","~$same",["^ ","~:row",57,"~:col",1,"~:fixed-arities",["~#set",[1]],"~:name","^0","~:ns","~$examples.ex00-introduction","~:top-ns","^7","~:type","~:fn"],"~$hie",["^ ","^1",215,"^2",1,"^3",["^4",[2]],"^5","^;","^6","^7","^8","^7","~:arities",["^ ","~i2",["^ ","~:ret","~:string","~:arglist-str","[person message]"]],"^9","^:"],"~:filename","/Users/zhangzixiong/Desktop/Workspace/Github/examples/clojure-examples/snippets/clojure-by-example/src/examples/ex00_introduction.clj"]
--------------------------------------------------------------------------------
/web/echo-server/test/echo_server/handler_test.clj:
--------------------------------------------------------------------------------
1 | (ns echo-server.handler-test
2 | (:require [clojure.test :refer :all]
3 | [ring.mock.request :as mock]
4 | [echo-server.handler :refer :all]))
5 |
6 | (deftest test-app
7 | (testing "main route"
8 | (let [response (app (mock/request :get "/"))]
9 | (is (= (:status response) 200))
10 | (is (= (:body response) "Hello World"))))
11 |
12 | (testing "not-found route"
13 | (let [response (app (mock/request :get "/invalid"))]
14 | (is (= (:status response) 404)))))
15 |
--------------------------------------------------------------------------------
/tutorials/clojure-by-example/.clj-kondo/.cache/v1/clj/clojure-by-example.ex00-introduction.transit.json:
--------------------------------------------------------------------------------
1 | ["^ ","~$same",["^ ","~:row",57,"~:col",1,"~:fixed-arities",["~#set",[1]],"~:name","^0","~:ns","~$clojure-by-example.ex00-introduction","~:top-ns","^7","~:type","~:fn"],"~$hie",["^ ","^1",215,"^2",1,"^3",["^4",[2]],"^5","^;","^6","^7","^8","^7","~:arities",["^ ","~i2",["^ ","~:ret","~:string","~:arglist-str","[person message]"]],"^9","^:"],"~:filename","/Users/zhangzixiong/Desktop/Workspace/Github/examples/clojure-examples/snippets/clojure-by-example/src/clojure_by_example/ex00_introduction.clj"]
--------------------------------------------------------------------------------
/web/echo-server/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/tutorials/clojure-by-example/project.clj:
--------------------------------------------------------------------------------
1 | (defproject clojure_by_example "0.1.0-SNAPSHOT"
2 | :description "A workshop to introduce Clojure, to programmers new to Clojure."
3 | :url "https://github.com/inclojure-org/clojure-by-example"
4 | :license {:name "MIT"
5 | :url "https://opensource.org/licenses/MIT"}
6 | ;; Requirements: Java 8 or higher (recommended: Java 8 or Java 11)
7 | :dependencies [[org.clojure/clojure "1.11.1"]]
8 | :local-repo ".m2-for-inclojure"
9 | :profiles {:dev {:dependencies [[org.clojure/data.json "2.4.0"]
10 | [enlive "1.1.6"]
11 | [rewrite-clj "1.1.46"]]}})
12 |
--------------------------------------------------------------------------------
/tutorials/clojure-by-example/resources/sensor_data/consolidated_data.json:
--------------------------------------------------------------------------------
1 | [{"mass":0.055,"radius":0.383,"moons":0,"atmosphere":{},"name":"Mercury"},{"mass":0.815,"radius":0.949,"moons":0,"atmosphere":{"carbon-dioxide":96.45,"nitrogen":3.45,"sulphur-dioxide":0.015,"traces":0.095},"name":"Venus"},{"mass":1,"radius":1,"moons":1,"atmosphere":{"nitrogen":78.08,"oxygen":20.95,"carbon-dioxide":0.4,"water-vapour":0.1,"argon":0.33,"traces":0.14},"name":"Earth"},{"mass":0.107,"radius":0.532,"moons":2,"atmosphere":{"carbon-dioxide":95.97,"argon":1.93,"nitrogen":1.89,"oxygen":0.146,"carbon-monoxide":0.056,"traces":0.008},"name":"Mars"},{"mass":2.5,"radius":1.3,"moons":4,"atmosphere":{"chlorine":100.0},"name":"Chlorine Planet"},{"mass":4.2,"radius":1.42,"moons":42,"atmosphere":{"sulphur-dioxide":80.0,"carbon-monoxide":10.0,"chlorine":5.0,"nitrogen":5.0},"name":"Insane Planet"}]
--------------------------------------------------------------------------------
/.clj-kondo/.cache/v1/clj/examples.fun.workshop-fmt.transit.json:
--------------------------------------------------------------------------------
1 | ["^ ","~$workshop-files!",["^ ","~:row",26,"~:col",1,"~:fixed-arities",["~#set",[2]],"~:name","^0","~:ns","~$examples.fun.workshop-fmt","~:top-ns","^7","~:type","~:fn"],"~$spit-root!",["^ ","^1",35,"^2",1,"^3",["^4",[2]],"^5","^;","^6","^7","^8","^7","^9","^:"],"~$elide-if-comment",["^ ","^1",12,"^2",1,"^3",["^4",[1]],"^5","^<","^6","^7","^8","^7","^9","^:"],"~$workshop-file-pattern",["^ ","^1",9,"^2",1,"^5","^=","^6","^7","^8","^7","^9","~:regex"],"~$elide-comment-forms",["^ ","^1",19,"^2",1,"^3",["^4",[1]],"^5","^?","^6","^7","^8","^7","^9","^:"],"~$relative-dest-path",["^ ","^1",8,"^2",1,"^5","^@","^6","^7","^8","^7","^9","~:string"],"~:filename","/Users/zhangzixiong/Desktop/Workspace/Github/examples/clojure-examples/snippets/clojure-by-example/src/examples/fun/workshop_fmt.clj","~$read-forms",["^ ","^1",70,"^2",3,"^3",["^4",[1]],"^5","^C","^6","^7","^8","^7","^9","^:"],"~$prep-workshop-code!",["^ ","^1",41,"^2",1,"^3",["^4",[3,2]],"^5","^D","^6","^7","^8","^7","^9","^:"],"~$relative-src-path",["^ ","^1",7,"^2",1,"^5","^E","^6","^7","^8","^7","^9","^A"]]
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 wx-chevalier
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/tutorials/clojure-by-example/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 | All notable changes to this project will be documented in this file. This change log follows the conventions of [keepachangelog.com](http://keepachangelog.com/).
3 |
4 | ## [Unreleased] - 2018-01-12
5 | ### Changed
6 | - The initial cut of this project, for use in the guided Clojure
7 | workshop at IN/Clojure 2018, Bangalore (http://inclojure.org/).
8 |
9 | ## [Unreleased] - 2018-01-18
10 | - Licensed under MIT, and assigned copyright to IN/Clojure for
11 | responsible stewardship, and in preparation for wider usage.
12 |
13 | ### Removed
14 | - A couple of NASA fact sheets that were committed while we were
15 | toying around with things. Removed due to unknown copyright status.
16 |
17 | ### Fixed
18 | - Fixed documentation, examples etc. based on workshop experience.
19 |
20 | ## [Unreleased] - 2018-01-19
21 | ### Fixed
22 | - Expanded setup in Readme to help more with editors and configurations.
23 | - Fixed project.clj to reflect the updated license
24 |
25 | [Unreleased]: https://github.com/inclojure-org/clojure-by-example/commit/035aa1e7f9c92ae04f639862e71b7148ac58864f
26 |
27 |
--------------------------------------------------------------------------------
/tutorials/clojure-by-example/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License
2 | Retrieved from https://opensource.org/licenses/MIT
3 | Retrieved on Thursday, 18 January 2018, 1800hrs IST.
4 |
5 | Copyright (c) 2017-2018 IN/Clojure
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
8 |
9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
10 |
11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12 |
--------------------------------------------------------------------------------
/.clj-kondo/.cache/v1/clj/examples.ex05-immutability-and-fp.transit.json:
--------------------------------------------------------------------------------
1 | ["^ ","~$scale-by-pi-v1",["^ ","~:row",145,"~:col",1,"~:fixed-arities",["~#set",[1]],"~:name","^0","~:ns","~$examples.ex05-immutability-and-fp","~:top-ns","^7","~:arities",["^ ","~i1",["^ ","~:ret","~:number","~:arglist-str","[n]"]],"~:type","~:fn"],"~$add-one!",["^ ","^1",234,"^2",1,"^3",["^4",[1]],"^5","^?","^6","^7","^8","^7","^9",["^ ","~i1",["^ ","^:","^;","^<","[x]"]],"^=","^>"],"~$pi",["^ ","^1",32,"^2",1,"^5","^@","^6","^7","^8","^7","^=","~:double"],"~$planets",["^ ","^1",62,"^2",1,"^5","^B","^6","^7","^8","^7","^=","~:vector"],"~$add-one",["^ ","^1",225,"^2",1,"^3",["^4",[1]],"^5","^D","^6","^7","^8","^7","^9",["^ ","~i1",["^ ","^:","^;","^<","[x]"]],"^=","^>"],"~$same",["^ ","^1",164,"^2",1,"^3",["^4",[1]],"^5","^E","^6","^7","^8","^7","^=","^>"],"~$scale-by-pi-v2",["^ ","^1",150,"^2",1,"^3",["^4",[1]],"^5","^F","^6","^7","^8","^7","^9",["^ ","~i1",["^ ","^:","^;","^<","[n]"]],"^=","^>"],"~:filename","/Users/zhangzixiong/Desktop/Workspace/Github/examples/clojure-examples/snippets/clojure-by-example/src/examples/ex05_immutability_and_fp.clj","~$other-pi",["^ ","^1",120,"^2",1,"^5","^H","^6","^7","^8","^7"],"~$weird-pi",["^ ","^1",118,"^2",1,"^5","^I","^6","^7","^8","^7","^=","~:pos-int"],"~$same-same",["^ ","^1",170,"^2",1,"^3",["^4",[1]],"^5","^K","^6","^7","^8","^7","^=","^>"]]
--------------------------------------------------------------------------------
/web/echo-server/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/tutorials/clojure-by-example/src/examples/ex08_but_before_we_go.clj:
--------------------------------------------------------------------------------
1 | (ns examples.ex08-but-before-we-go)
2 |
3 | ;; But before we boldly go, here are some resources to help us on our journey!
4 |
5 | ;; Check out the official website: https://clojure.org
6 |
7 | ;; It has been accumulating many useful tutorials, guides, book references,
8 | ;; community resources, and information about companies using Clojure.
9 |
10 | ;; Also, here are a few things we really like and find useful to aid understanding
11 | ;; at various levels; from the philosophical to the here and now:
12 |
13 | ;; Talks/Philosphy:
14 | ;; https://www.youtube.com/watch?v=wASCH_gPnDw -- Inside Clojure with Brian Beckman and Rich Hickey
15 | ;; https://www.infoq.com/presentations/Value-Values -- The Value of Values by Rich Hickey
16 | ;; https://www.infoq.com/presentations/Value-Identity-State-Rich-Hickey -- Persistent Data Structures and Managed References by Rich Hickey
17 | ;; https://www.infoq.com/presentations/Simple-Made-Easy -- Simple Made Easy by Rich Hickey
18 |
19 | ;; Debugging:
20 | ;;
21 | ;; - "Inside-out"/"Bottom-up" REPL-driven debugging, particularly how
22 | ;; Stu Halloway explains, in "Debugging With the Scientific Method".
23 | ;; https://www.youtube.com/watch?v=FihU5JxmnBg
24 | ;;
25 | ;; - Aphyr's post is neat!
26 | ;; - Scroll down to the "Debugging Clojure" section:
27 | ;; https://aphyr.com/posts/319-clojure-from-the-ground-up-debugging
28 |
29 | ;; Handy REPL utils:
30 | ;;
31 | ;; - clojure.repl/
32 | ;; - source, doc, pp, pprint, print-table
33 | ;; - see the bottom of the `clojure-by-example.utils.core` ns
34 | ;;
35 | ;; - *1, *2, *3, *e
36 | ;;
37 | ;; - A sane REPL workflow (buffer/file-based, rather than inside REPL)
38 | ;;
39 |
--------------------------------------------------------------------------------
/.clj-kondo/.cache/v1/clj/examples.ex06-full-functional-firepower.transit.json:
--------------------------------------------------------------------------------
1 | ["^ ","~$ingest-export-sensor-data!",["^ ","~:row",247,"~:col",1,"~:fixed-arities",["~#set",[3]],"~:name","^0","~:ns","~$examples.ex06-full-functional-firepower","~:top-ns","^7","~:type","~:fn"],"~$sensor-data-dir",["^ ","^1",107,"^2",1,"^5","^;","^6","^7","^8","^7","^9","~:string"],"~$denormalise-planetary-data",["^ ","^1",218,"^2",1,"^3",["^4",[1]],"^5","^=","^6","^7","^8","^7","^9","^:"],"~$add-atmosphere-data",["^ ","^1",198,"^2",1,"^3",["^4",[2]],"^5","^>","^6","^7","^8","^7","^9","^:"],"~$add-sensor-data",["^ ","^1",177,"^2",1,"^3",["^4",[3]],"^5","^?","^6","^7","^8","^7","~:arities",["^ ","~i3",["^ ","~:ret","~:associative","~:arglist-str","[sensor-key planets [pname sensor-pdata]]"]],"^9","^:"],"~$consolidated-data-file",["^ ","^1",133,"^2",1,"^5","^D","^6","^7","^8","^7","^9","^<"],"~$sensor-data-files",["^ ","^1",119,"^2",1,"^5","^E","^6","^7","^8","^7","^9",["^ ","^9","~:map","~:val",["^ ","~:planets",["^ ","^1",121,"^2",13,"~:end-row",121,"~:end-col",35,"~:tag","^<"],"~:moons",["^ ","^1",124,"^2",11,"^I",124,"^J",31,"^K","^<"],"~:atmosphere",["^ ","^1",127,"^2",16,"^I",127,"^J",43,"^K","^<"]]]],"~:filename","/Users/zhangzixiong/Desktop/Workspace/Github/examples/clojure-examples/snippets/clojure-by-example/src/examples/ex06_full_functional_firepower.clj","~$ingest-json-file!",["^ ","^1",149,"^2",1,"^3",["^4",[2]],"^5","^O","^6","^7","^8","^7","^9","^:"],"~$gather-all-sensor-data!",["^ ","^1",157,"^2",1,"^3",["^4",[2]],"^5","^P","^6","^7","^8","^7","^9","^:"],"~$add-moon-data",["^ ","^1",190,"^2",1,"^3",["^4",[2]],"^5","^Q","^6","^7","^8","^7","^9","^:"],"~$write-out-json-file!",["^ ","^1",240,"^2",1,"^3",["^4",[3]],"^5","^R","^6","^7","^8","^7","^9","^:"],"~$denormalise-planetary-data*",["^ ","^1",206,"^2",1,"^3",["^4",[1]],"^5","^S","^6","^7","^8","^7","^@",["^ ","~i1",["^ ","^A","~:seq","^C","[planets]"]],"^9","^:"]]
--------------------------------------------------------------------------------
/tutorials/clojure-by-example/.clj-kondo/.cache/v1/clj/clojure-by-example.ex06-full-functional-firepower.transit.json:
--------------------------------------------------------------------------------
1 | ["^ ","~$ingest-export-sensor-data!",["^ ","~:row",247,"~:col",1,"~:fixed-arities",["~#set",[3]],"~:name","^0","~:ns","~$clojure-by-example.ex06-full-functional-firepower","~:top-ns","^7","~:type","~:fn"],"~$sensor-data-dir",["^ ","^1",107,"^2",1,"^5","^;","^6","^7","^8","^7","^9","~:string"],"~$denormalise-planetary-data",["^ ","^1",218,"^2",1,"^3",["^4",[1]],"^5","^=","^6","^7","^8","^7","^9","^:"],"~$add-atmosphere-data",["^ ","^1",198,"^2",1,"^3",["^4",[2]],"^5","^>","^6","^7","^8","^7","^9","^:"],"~$add-sensor-data",["^ ","^1",177,"^2",1,"^3",["^4",[3]],"^5","^?","^6","^7","^8","^7","~:arities",["^ ","~i3",["^ ","~:ret","~:associative","~:arglist-str","[sensor-key planets [pname sensor-pdata]]"]],"^9","^:"],"~$consolidated-data-file",["^ ","^1",133,"^2",1,"^5","^D","^6","^7","^8","^7","^9","^<"],"~$sensor-data-files",["^ ","^1",119,"^2",1,"^5","^E","^6","^7","^8","^7","^9",["^ ","^9","~:map","~:val",["^ ","~:planets",["^ ","^1",121,"^2",13,"~:end-row",121,"~:end-col",35,"~:tag","^<"],"~:moons",["^ ","^1",124,"^2",11,"^I",124,"^J",31,"^K","^<"],"~:atmosphere",["^ ","^1",127,"^2",16,"^I",127,"^J",43,"^K","^<"]]]],"~:filename","/Users/zhangzixiong/Desktop/Workspace/Github/examples/clojure-examples/snippets/clojure-by-example/src/examples/ex06_full_functional_firepower.clj","~$ingest-json-file!",["^ ","^1",149,"^2",1,"^3",["^4",[2]],"^5","^O","^6","^7","^8","^7","^9","^:"],"~$gather-all-sensor-data!",["^ ","^1",157,"^2",1,"^3",["^4",[2]],"^5","^P","^6","^7","^8","^7","^9","^:"],"~$add-moon-data",["^ ","^1",190,"^2",1,"^3",["^4",[2]],"^5","^Q","^6","^7","^8","^7","^9","^:"],"~$write-out-json-file!",["^ ","^1",240,"^2",1,"^3",["^4",[3]],"^5","^R","^6","^7","^8","^7","^9","^:"],"~$denormalise-planetary-data*",["^ ","^1",206,"^2",1,"^3",["^4",[1]],"^5","^S","^6","^7","^8","^7","^@",["^ ","~i1",["^ ","^A","~:seq","^C","[planets]"]],"^9","^:"]]
--------------------------------------------------------------------------------
/tutorials/clojure-by-example/src/examples/data/planets.clj:
--------------------------------------------------------------------------------
1 | (ns examples.data.planets)
2 |
3 | (def target-planets
4 | [{:pname "Mercury"
5 | :mass 0.055
6 | :radius 0.383
7 | :moons 0
8 | :gravity 0.378
9 | :surface-pressure 0
10 | :surface-temp-deg-c {:low -170 :high 449}
11 | :rocky? true
12 | :atmosphere {}} ; empty hash map means no atmosphere
13 |
14 | {:pname "Venus"
15 | :mass 0.815
16 | :radius 0.949
17 | :moons 0
18 | :gravity 0.907
19 | :surface-pressure 92
20 | :surface-temp-deg-c {:low 465 :high 465}
21 | :rocky? true
22 | :atmosphere {:carbon-dioxide 96.45 :nitrogen 3.45
23 | :sulphur-dioxide 0.015 :traces 0.095}}
24 |
25 | {:pname "Earth"
26 | :mass 1
27 | :radius 1
28 | :moons 1
29 | :gravity 1
30 | :surface-pressure 1
31 | :surface-temp-deg-c {:low -89 :high 58}
32 | :rocky? true
33 | :atmosphere {:nitrogen 78.08 :oxygen 20.95 :carbon-dioxide 0.4
34 | :water-vapour 0.10 :argon 0.33 :traces 0.14}}
35 |
36 | {:pname "Mars"
37 | :mass 0.107
38 | :radius 0.532
39 | :moons 2
40 | :gravity 0.377
41 | :surface-pressure 0.01
42 | :surface-temp-deg-c {:low -125 :high 20}
43 | :rocky? true
44 | :atmosphere {:carbon-dioxide 95.97 :argon 1.93 :nitrogen 1.89
45 | :oxygen 0.146 :carbon-monoxide 0.056 :traces 0.008}}
46 |
47 | {:pname "Chlorine Planet"
48 | :mass 2.5
49 | :radius 1.3
50 | :moons 4
51 | :gravity 1.5
52 | :surface-pressure 1
53 | :surface-temp-deg-c {:low -42 :high 24}
54 | :rocky? true
55 | :atmosphere {:chlorine 100.0}}
56 |
57 | {:pname "Insane Planet"
58 | :mass 42
59 | :radius 4.2
60 | :moons 42
61 | :gravity 10
62 | :surface-pressure 420
63 | :surface-temp-deg-c {:low 750 :high 750}
64 | :rocky? false
65 | :atmosphere {:sulphur-dioxide 80.0 :carbon-monoxide 10.0
66 | :chlorine 5.0 :nitrogen 5.0}}])
67 |
--------------------------------------------------------------------------------
/.clj-kondo/.cache/v1/clj/examples.ex01-fundamentally-functional.transit.json:
--------------------------------------------------------------------------------
1 | ["^ ","~$x",["^ ","~:row",253,"~:col",1,"~:name","~$x","~:ns","~$examples.ex01-fundamentally-functional","~:top-ns","^4","~:type","~:pos-int"],"~$function-name",["^ ","^0",25,"^1",1,"~:fixed-arities",["~#set",[7]],"^2","^8","^3","^4","^5","^4","~:arities",["^ ","~i7",["^ ","~:ret","~:symbol","~:arglist-str","[arg1 arg2 arg3 etc up to argN]"]],"^6","~:fn"],"~$halve",["^ ","^0",356,"^1",3,"^2","^@","^3","^4","^5","^4","^6","^="],"~$gen-identity-v2",["^ ","^0",141,"^1",1,"^9",["^:",[0]],"^2","^A","^3","^4","^5","^4","^;",["^ ","~i0",["^ ","^<","^=","^>","[]"]],"^6","^?"],"~$scale-by",["^ ","^0",331,"^1",1,"^9",["^:",[1]],"^2","^B","^3","^4","^5","^4","^;",["^ ","~i1",["^ ","^<","^?","^>","[x]"]],"^6","^?"],"~$same",["^ ","^0",43,"^1",1,"^9",["^:",[1]],"^2","^C","^3","^4","^5","^4","^6","^?"],"~$PI",["^ ","^0",319,"^1",1,"^2","^D","^3","^4","^5","^4","^6","~:double"],"~$add-one-v2",["^ ","^0",278,"^1",1,"^9",["^:",[1]],"^2","^F","^3","^4","^5","^4","^;",["^ ","~i1",["^ ","^<","~:number","^>","[z]"]],"^6","^?"],"~:filename","/Users/zhangzixiong/Desktop/Workspace/Github/examples/clojure-examples/snippets/clojure-by-example/src/examples/ex01_fundamentally_functional.clj","~$selfie",["^ ","^0",170,"^1",1,"^9",["^:",[1]],"^2","^I","^3","^4","^5","^4","^6","^?"],"~$scale-by-PI",["^ ","^0",321,"^1",1,"^9",["^:",[1]],"^2","^J","^3","^4","^5","^4","^;",["^ ","~i1",["^ ","^<","^G","^>","[n]"]],"^6","^?"],"~$add-one-v1",["^ ","^0",270,"^1",1,"^9",["^:",[1]],"^2","^K","^3","^4","^5","^4","^;",["^ ","~i1",["^ ","^<","^G","^>","[x]"]],"^6","^?"],"~$quadruple",["^ ","^0",352,"^1",3,"^2","^L","^3","^4","^5","^4","^6","^="],"~$gen-identity",["^ ","^0",133,"^1",1,"^9",["^:",[0]],"^2","^M","^3","^4","^5","^4","^;",["^ ","~i0",["^ ","^<","^=","^>","[]"]],"^6","^?"],"~$add-one-v3",["^ ","^0",286,"^1",1,"^9",["^:",[1]],"^2","^N","^3","^4","^5","^4","^;",["^ ","~i1",["^ ","^<","^G","^>","[x]"]],"^6","^?"],"~$a-bunch-of-values",["^ ","^0",449,"^1",1,"^2","^O","^3","^4","^5","^4","^6","~:vector"],"~$scale-by-PI-v2",["^ ","^0",349,"^1",3,"^2","^Q","^3","^4","^5","^4","^6","^="]]
--------------------------------------------------------------------------------
/tutorials/clojure-by-example/.clj-kondo/.cache/v1/clj/examples.ex01-fundamentally-functional.transit.json:
--------------------------------------------------------------------------------
1 | ["^ ","~$x",["^ ","~:row",253,"~:col",1,"~:name","~$x","~:ns","~$examples.ex01-fundamentally-functional","~:top-ns","^4","~:type","~:pos-int"],"~$function-name",["^ ","^0",25,"^1",1,"~:fixed-arities",["~#set",[7]],"^2","^8","^3","^4","^5","^4","~:arities",["^ ","~i7",["^ ","~:ret","~:symbol","~:arglist-str","[arg1 arg2 arg3 etc up to argN]"]],"^6","~:fn"],"~$halve",["^ ","^0",356,"^1",3,"^2","^@","^3","^4","^5","^4","^6","^="],"~$gen-identity-v2",["^ ","^0",141,"^1",1,"^9",["^:",[0]],"^2","^A","^3","^4","^5","^4","^;",["^ ","~i0",["^ ","^<","^=","^>","[]"]],"^6","^?"],"~$scale-by",["^ ","^0",331,"^1",1,"^9",["^:",[1]],"^2","^B","^3","^4","^5","^4","^;",["^ ","~i1",["^ ","^<","^?","^>","[x]"]],"^6","^?"],"~$same",["^ ","^0",43,"^1",1,"^9",["^:",[1]],"^2","^C","^3","^4","^5","^4","^6","^?"],"~$PI",["^ ","^0",319,"^1",1,"^2","^D","^3","^4","^5","^4","^6","~:double"],"~$add-one-v2",["^ ","^0",278,"^1",1,"^9",["^:",[1]],"^2","^F","^3","^4","^5","^4","^;",["^ ","~i1",["^ ","^<","~:number","^>","[z]"]],"^6","^?"],"~:filename","/Users/zhangzixiong/Desktop/Workspace/Github/examples/clojure-examples/snippets/clojure-by-example/src/examples/ex01_fundamentally_functional.clj","~$selfie",["^ ","^0",170,"^1",1,"^9",["^:",[1]],"^2","^I","^3","^4","^5","^4","^6","^?"],"~$scale-by-PI",["^ ","^0",321,"^1",1,"^9",["^:",[1]],"^2","^J","^3","^4","^5","^4","^;",["^ ","~i1",["^ ","^<","^G","^>","[n]"]],"^6","^?"],"~$add-one-v1",["^ ","^0",270,"^1",1,"^9",["^:",[1]],"^2","^K","^3","^4","^5","^4","^;",["^ ","~i1",["^ ","^<","^G","^>","[x]"]],"^6","^?"],"~$quadruple",["^ ","^0",352,"^1",3,"^2","^L","^3","^4","^5","^4","^6","^="],"~$gen-identity",["^ ","^0",133,"^1",1,"^9",["^:",[0]],"^2","^M","^3","^4","^5","^4","^;",["^ ","~i0",["^ ","^<","^=","^>","[]"]],"^6","^?"],"~$add-one-v3",["^ ","^0",286,"^1",1,"^9",["^:",[1]],"^2","^N","^3","^4","^5","^4","^;",["^ ","~i1",["^ ","^<","^G","^>","[x]"]],"^6","^?"],"~$a-bunch-of-values",["^ ","^0",449,"^1",1,"^2","^O","^3","^4","^5","^4","^6","~:vector"],"~$scale-by-PI-v2",["^ ","^0",349,"^1",3,"^2","^Q","^3","^4","^5","^4","^6","^="]]
--------------------------------------------------------------------------------
/tutorials/clojure-by-example/.clj-kondo/.cache/v1/clj/clojure-by-example.ex01-fundamentally-functional.transit.json:
--------------------------------------------------------------------------------
1 | ["^ ","~$x",["^ ","~:row",253,"~:col",1,"~:name","~$x","~:ns","~$clojure-by-example.ex01-fundamentally-functional","~:top-ns","^4","~:type","~:pos-int"],"~$function-name",["^ ","^0",25,"^1",1,"~:fixed-arities",["~#set",[7]],"^2","^8","^3","^4","^5","^4","~:arities",["^ ","~i7",["^ ","~:ret","~:symbol","~:arglist-str","[arg1 arg2 arg3 etc up to argN]"]],"^6","~:fn"],"~$halve",["^ ","^0",356,"^1",3,"^2","^@","^3","^4","^5","^4","^6","^="],"~$gen-identity-v2",["^ ","^0",141,"^1",1,"^9",["^:",[0]],"^2","^A","^3","^4","^5","^4","^;",["^ ","~i0",["^ ","^<","^=","^>","[]"]],"^6","^?"],"~$scale-by",["^ ","^0",331,"^1",1,"^9",["^:",[1]],"^2","^B","^3","^4","^5","^4","^;",["^ ","~i1",["^ ","^<","^?","^>","[x]"]],"^6","^?"],"~$same",["^ ","^0",43,"^1",1,"^9",["^:",[1]],"^2","^C","^3","^4","^5","^4","^6","^?"],"~$PI",["^ ","^0",319,"^1",1,"^2","^D","^3","^4","^5","^4","^6","~:double"],"~$add-one-v2",["^ ","^0",278,"^1",1,"^9",["^:",[1]],"^2","^F","^3","^4","^5","^4","^;",["^ ","~i1",["^ ","^<","~:number","^>","[z]"]],"^6","^?"],"~:filename","/Users/zhangzixiong/Desktop/Workspace/Github/examples/clojure-examples/snippets/clojure-by-example/src/examples/ex01_fundamentally_functional.clj","~$selfie",["^ ","^0",170,"^1",1,"^9",["^:",[1]],"^2","^I","^3","^4","^5","^4","^6","^?"],"~$scale-by-PI",["^ ","^0",321,"^1",1,"^9",["^:",[1]],"^2","^J","^3","^4","^5","^4","^;",["^ ","~i1",["^ ","^<","^G","^>","[n]"]],"^6","^?"],"~$add-one-v1",["^ ","^0",270,"^1",1,"^9",["^:",[1]],"^2","^K","^3","^4","^5","^4","^;",["^ ","~i1",["^ ","^<","^G","^>","[x]"]],"^6","^?"],"~$quadruple",["^ ","^0",352,"^1",3,"^2","^L","^3","^4","^5","^4","^6","^="],"~$gen-identity",["^ ","^0",133,"^1",1,"^9",["^:",[0]],"^2","^M","^3","^4","^5","^4","^;",["^ ","~i0",["^ ","^<","^=","^>","[]"]],"^6","^?"],"~$add-one-v3",["^ ","^0",286,"^1",1,"^9",["^:",[1]],"^2","^N","^3","^4","^5","^4","^;",["^ ","~i1",["^ ","^<","^G","^>","[x]"]],"^6","^?"],"~$a-bunch-of-values",["^ ","^0",449,"^1",1,"^2","^O","^3","^4","^5","^4","^6","~:vector"],"~$scale-by-PI-v2",["^ ","^0",349,"^1",3,"^2","^Q","^3","^4","^5","^4","^6","^="]]
--------------------------------------------------------------------------------
/.clj-kondo/.cache/v1/clj/examples.ex02-domain-as-data.transit.json:
--------------------------------------------------------------------------------
1 | ["^ ","~$earth",["^ ","~:row",26,"~:col",1,"~:name","^0","~:ns","~$examples.ex02-domain-as-data","~:top-ns","^5","~:type",["^ ","^7","~:map","~:val",["^ ","pname",["^ ","^1",27,"^2",12,"~:end-row",27,"~:end-col",19,"~:tag","~:string"],"mass",["^ ","^1",28,"^2",13,"^;",28,"^<",14,"^=","~:pos-int"],"radius",["^ ","^1",29,"^2",13,"^;",29,"^<",14,"^=","^@"],"moons",["^ ","^1",30,"^2",13,"^;",30,"^<",14,"^=","^@"],"atmosphere",["^ ","^1",31,"^2",17,"^;",36,"^<",40,"^=",["^ ","^7","^8","^9",["^ ","nitrogen",["^ ","^1",31,"^2",35,"^;",31,"^<",40,"^=","~:double"],"oxygen",["^ ","^1",32,"^2",35,"^;",32,"^<",40,"^=","^E"],"carbon-dioxide",["^ ","^1",33,"^2",35,"^;",33,"^<",38,"^=","^E"],"water-vapour",["^ ","^1",34,"^2",35,"^;",34,"^<",39,"^=","^E"],"argon",["^ ","^1",35,"^2",35,"^;",35,"^<",39,"^=","^E"],"traces",["^ ","^1",36,"^2",35,"^;",36,"^<",39,"^=","^E"]]]]]]],"~$earth-alt",["^ ","^1",57,"^2",1,"^3","^K","^4","^5","^6","^5","^7",["^ ","^7","^8","^9",["^ ","~:pname",["^ ","^1",58,"^2",11,"^;",58,"^<",18,"^=","^>"],"~:mass",["^ ","^1",59,"^2",10,"^;",59,"^<",11,"^=","^@"],"~:radius",["^ ","^1",60,"^2",12,"^;",60,"^<",13,"^=","^@"],"~:moons",["^ ","^1",61,"^2",11,"^;",61,"^<",12,"^=","^@"],"~:atmosphere",["^ ","^1",62,"^2",16,"^;",67,"^<",30,"^=",["^ ","^7","^8","^9",["^ ","~:nitrogen",["^ ","^1",62,"^2",27,"^;",62,"^<",32,"^=","^E"],"~:oxygen",["^ ","^1",63,"^2",25,"^;",63,"^<",30,"^=","^E"],"~:carbon-dioxide",["^ ","^1",64,"^2",33,"^;",64,"^<",36,"^=","^E"],"~:water-vapour",["^ ","^1",65,"^2",31,"^;",65,"^<",35,"^=","^E"],"~:argon",["^ ","^1",66,"^2",24,"^;",66,"^<",28,"^=","^E"],"~:traces",["^ ","^1",67,"^2",25,"^;",67,"^<",29,"^=","^E"]]]]]]],"~$planets",["^ ","^1",97,"^2",1,"^3","^W","^4","^5","^6","^5","^7","~:vector"],"~$less-mass-than-earth?",["^ ","^1",116,"^2",1,"~:fixed-arities",["~#set",[1]],"^3","^Y","^4","^5","^6","^5","~:arities",["^ ","~i1",["^ ","~:ret","~:boolean","~:arglist-str","[planet]"]],"^7","~:fn"],"~$poison-gas?",["^ ","^1",165,"^2",1,"^3","^15","^4","^5","^6","^5","^7","~:symbol"],"~$a-bunch-of-values",["^ ","^1",177,"^2",1,"^3","^17","^4","^5","^6","^5","^7","^X"],"~:filename","/Users/zhangzixiong/Desktop/Workspace/Github/examples/clojure-examples/snippets/clojure-by-example/src/examples/ex02_domain_as_data.clj"]
--------------------------------------------------------------------------------
/.clj-kondo/.cache/v1/clj/clojure-by-example.ex02-domain-as-data.transit.json:
--------------------------------------------------------------------------------
1 | ["^ ","~$earth",["^ ","~:row",26,"~:col",1,"~:name","^0","~:ns","~$clojure-by-example.ex02-domain-as-data","~:top-ns","^5","~:type",["^ ","^7","~:map","~:val",["^ ","pname",["^ ","^1",27,"^2",12,"~:end-row",27,"~:end-col",19,"~:tag","~:string"],"mass",["^ ","^1",28,"^2",13,"^;",28,"^<",14,"^=","~:pos-int"],"radius",["^ ","^1",29,"^2",13,"^;",29,"^<",14,"^=","^@"],"moons",["^ ","^1",30,"^2",13,"^;",30,"^<",14,"^=","^@"],"atmosphere",["^ ","^1",31,"^2",17,"^;",36,"^<",40,"^=",["^ ","^7","^8","^9",["^ ","nitrogen",["^ ","^1",31,"^2",35,"^;",31,"^<",40,"^=","~:double"],"oxygen",["^ ","^1",32,"^2",35,"^;",32,"^<",40,"^=","^E"],"carbon-dioxide",["^ ","^1",33,"^2",35,"^;",33,"^<",38,"^=","^E"],"water-vapour",["^ ","^1",34,"^2",35,"^;",34,"^<",39,"^=","^E"],"argon",["^ ","^1",35,"^2",35,"^;",35,"^<",39,"^=","^E"],"traces",["^ ","^1",36,"^2",35,"^;",36,"^<",39,"^=","^E"]]]]]]],"~$earth-alt",["^ ","^1",57,"^2",1,"^3","^K","^4","^5","^6","^5","^7",["^ ","^7","^8","^9",["^ ","~:pname",["^ ","^1",58,"^2",11,"^;",58,"^<",18,"^=","^>"],"~:mass",["^ ","^1",59,"^2",10,"^;",59,"^<",11,"^=","^@"],"~:radius",["^ ","^1",60,"^2",12,"^;",60,"^<",13,"^=","^@"],"~:moons",["^ ","^1",61,"^2",11,"^;",61,"^<",12,"^=","^@"],"~:atmosphere",["^ ","^1",62,"^2",16,"^;",67,"^<",30,"^=",["^ ","^7","^8","^9",["^ ","~:nitrogen",["^ ","^1",62,"^2",27,"^;",62,"^<",32,"^=","^E"],"~:oxygen",["^ ","^1",63,"^2",25,"^;",63,"^<",30,"^=","^E"],"~:carbon-dioxide",["^ ","^1",64,"^2",33,"^;",64,"^<",36,"^=","^E"],"~:water-vapour",["^ ","^1",65,"^2",31,"^;",65,"^<",35,"^=","^E"],"~:argon",["^ ","^1",66,"^2",24,"^;",66,"^<",28,"^=","^E"],"~:traces",["^ ","^1",67,"^2",25,"^;",67,"^<",29,"^=","^E"]]]]]]],"~$planets",["^ ","^1",97,"^2",1,"^3","^W","^4","^5","^6","^5","^7","~:vector"],"~$less-mass-than-earth?",["^ ","^1",116,"^2",1,"~:fixed-arities",["~#set",[1]],"^3","^Y","^4","^5","^6","^5","~:arities",["^ ","~i1",["^ ","~:ret","~:boolean","~:arglist-str","[planet]"]],"^7","~:fn"],"~$poison-gas?",["^ ","^1",165,"^2",1,"^3","^15","^4","^5","^6","^5","^7","~:symbol"],"~$a-bunch-of-values",["^ ","^1",177,"^2",1,"^3","^17","^4","^5","^6","^5","^7","^X"],"~:filename","/Users/zhangzixiong/Desktop/Workspace/Github/examples/clojure-examples/snippets/clojure-by-example/src/examples/ex02_domain_as_data.clj"]
--------------------------------------------------------------------------------
/tutorials/clojure-by-example/.clj-kondo/.cache/v1/clj/examples.ex02-domain-as-data.transit.json:
--------------------------------------------------------------------------------
1 | ["^ ","~$earth",["^ ","~:row",26,"~:col",1,"~:name","^0","~:ns","~$examples.ex02-domain-as-data","~:top-ns","^5","~:type",["^ ","^7","~:map","~:val",["^ ","pname",["^ ","^1",27,"^2",12,"~:end-row",27,"~:end-col",19,"~:tag","~:string"],"mass",["^ ","^1",28,"^2",13,"^;",28,"^<",14,"^=","~:pos-int"],"radius",["^ ","^1",29,"^2",13,"^;",29,"^<",14,"^=","^@"],"moons",["^ ","^1",30,"^2",13,"^;",30,"^<",14,"^=","^@"],"atmosphere",["^ ","^1",31,"^2",17,"^;",36,"^<",40,"^=",["^ ","^7","^8","^9",["^ ","nitrogen",["^ ","^1",31,"^2",35,"^;",31,"^<",40,"^=","~:double"],"oxygen",["^ ","^1",32,"^2",35,"^;",32,"^<",40,"^=","^E"],"carbon-dioxide",["^ ","^1",33,"^2",35,"^;",33,"^<",38,"^=","^E"],"water-vapour",["^ ","^1",34,"^2",35,"^;",34,"^<",39,"^=","^E"],"argon",["^ ","^1",35,"^2",35,"^;",35,"^<",39,"^=","^E"],"traces",["^ ","^1",36,"^2",35,"^;",36,"^<",39,"^=","^E"]]]]]]],"~$earth-alt",["^ ","^1",57,"^2",1,"^3","^K","^4","^5","^6","^5","^7",["^ ","^7","^8","^9",["^ ","~:pname",["^ ","^1",58,"^2",11,"^;",58,"^<",18,"^=","^>"],"~:mass",["^ ","^1",59,"^2",10,"^;",59,"^<",11,"^=","^@"],"~:radius",["^ ","^1",60,"^2",12,"^;",60,"^<",13,"^=","^@"],"~:moons",["^ ","^1",61,"^2",11,"^;",61,"^<",12,"^=","^@"],"~:atmosphere",["^ ","^1",62,"^2",16,"^;",67,"^<",30,"^=",["^ ","^7","^8","^9",["^ ","~:nitrogen",["^ ","^1",62,"^2",27,"^;",62,"^<",32,"^=","^E"],"~:oxygen",["^ ","^1",63,"^2",25,"^;",63,"^<",30,"^=","^E"],"~:carbon-dioxide",["^ ","^1",64,"^2",33,"^;",64,"^<",36,"^=","^E"],"~:water-vapour",["^ ","^1",65,"^2",31,"^;",65,"^<",35,"^=","^E"],"~:argon",["^ ","^1",66,"^2",24,"^;",66,"^<",28,"^=","^E"],"~:traces",["^ ","^1",67,"^2",25,"^;",67,"^<",29,"^=","^E"]]]]]]],"~$planets",["^ ","^1",97,"^2",1,"^3","^W","^4","^5","^6","^5","^7","~:vector"],"~$less-mass-than-earth?",["^ ","^1",116,"^2",1,"~:fixed-arities",["~#set",[1]],"^3","^Y","^4","^5","^6","^5","~:arities",["^ ","~i1",["^ ","~:ret","~:boolean","~:arglist-str","[planet]"]],"^7","~:fn"],"~$poison-gas?",["^ ","^1",165,"^2",1,"^3","^15","^4","^5","^6","^5","^7","~:symbol"],"~$a-bunch-of-values",["^ ","^1",177,"^2",1,"^3","^17","^4","^5","^6","^5","^7","^X"],"~:filename","/Users/zhangzixiong/Desktop/Workspace/Github/examples/clojure-examples/snippets/clojure-by-example/src/examples/ex02_domain_as_data.clj"]
--------------------------------------------------------------------------------
/tutorials/clojure-by-example/.clj-kondo/.cache/v1/clj/clojure-by-example.ex02-domain-as-data.transit.json:
--------------------------------------------------------------------------------
1 | ["^ ","~$earth",["^ ","~:row",26,"~:col",1,"~:name","^0","~:ns","~$clojure-by-example.ex02-domain-as-data","~:top-ns","^5","~:type",["^ ","^7","~:map","~:val",["^ ","pname",["^ ","^1",27,"^2",12,"~:end-row",27,"~:end-col",19,"~:tag","~:string"],"mass",["^ ","^1",28,"^2",13,"^;",28,"^<",14,"^=","~:pos-int"],"radius",["^ ","^1",29,"^2",13,"^;",29,"^<",14,"^=","^@"],"moons",["^ ","^1",30,"^2",13,"^;",30,"^<",14,"^=","^@"],"atmosphere",["^ ","^1",31,"^2",17,"^;",36,"^<",40,"^=",["^ ","^7","^8","^9",["^ ","nitrogen",["^ ","^1",31,"^2",35,"^;",31,"^<",40,"^=","~:double"],"oxygen",["^ ","^1",32,"^2",35,"^;",32,"^<",40,"^=","^E"],"carbon-dioxide",["^ ","^1",33,"^2",35,"^;",33,"^<",38,"^=","^E"],"water-vapour",["^ ","^1",34,"^2",35,"^;",34,"^<",39,"^=","^E"],"argon",["^ ","^1",35,"^2",35,"^;",35,"^<",39,"^=","^E"],"traces",["^ ","^1",36,"^2",35,"^;",36,"^<",39,"^=","^E"]]]]]]],"~$earth-alt",["^ ","^1",57,"^2",1,"^3","^K","^4","^5","^6","^5","^7",["^ ","^7","^8","^9",["^ ","~:pname",["^ ","^1",58,"^2",11,"^;",58,"^<",18,"^=","^>"],"~:mass",["^ ","^1",59,"^2",10,"^;",59,"^<",11,"^=","^@"],"~:radius",["^ ","^1",60,"^2",12,"^;",60,"^<",13,"^=","^@"],"~:moons",["^ ","^1",61,"^2",11,"^;",61,"^<",12,"^=","^@"],"~:atmosphere",["^ ","^1",62,"^2",16,"^;",67,"^<",30,"^=",["^ ","^7","^8","^9",["^ ","~:nitrogen",["^ ","^1",62,"^2",27,"^;",62,"^<",32,"^=","^E"],"~:oxygen",["^ ","^1",63,"^2",25,"^;",63,"^<",30,"^=","^E"],"~:carbon-dioxide",["^ ","^1",64,"^2",33,"^;",64,"^<",36,"^=","^E"],"~:water-vapour",["^ ","^1",65,"^2",31,"^;",65,"^<",35,"^=","^E"],"~:argon",["^ ","^1",66,"^2",24,"^;",66,"^<",28,"^=","^E"],"~:traces",["^ ","^1",67,"^2",25,"^;",67,"^<",29,"^=","^E"]]]]]]],"~$planets",["^ ","^1",97,"^2",1,"^3","^W","^4","^5","^6","^5","^7","~:vector"],"~$less-mass-than-earth?",["^ ","^1",116,"^2",1,"~:fixed-arities",["~#set",[1]],"^3","^Y","^4","^5","^6","^5","~:arities",["^ ","~i1",["^ ","~:ret","~:boolean","~:arglist-str","[planet]"]],"^7","~:fn"],"~$poison-gas?",["^ ","^1",165,"^2",1,"^3","^15","^4","^5","^6","^5","^7","~:symbol"],"~$a-bunch-of-values",["^ ","^1",177,"^2",1,"^3","^17","^4","^5","^6","^5","^7","^X"],"~:filename","/Users/zhangzixiong/Desktop/Workspace/Github/examples/clojure-examples/snippets/clojure-by-example/src/examples/ex02_domain_as_data.clj"]
--------------------------------------------------------------------------------
/.clj-kondo/.cache/v1/clj/examples.fun.inspect-nasa-planets.transit.json:
--------------------------------------------------------------------------------
1 | ["^ ","~$file->html-resource",["^ ","~:row",42,"~:col",1,"~:fixed-arities",["~#set",[1]],"~:name","^0","~:ns","~$examples.fun.inspect-nasa-planets","~:top-ns","^7","~:type","~:fn"],"~$extract-raw-data",["^ ","^1",77,"^2",1,"^3",["^4",[1]],"^5","^;","^6","^7","^8","^7","~:arities",["^ ","~i1",["^ ","~:ret","~:nilable/map","~:arglist-str","[{:keys [html-resource stats-path rows-label-path cols-label-path] :as table-info}]"]],"^9","^:"],"~$transpose-matrix",["^ ","^1",174,"^2",1,"^3",["^4",[1]],"^5","^@","^6","^7","^8","^7","^9","^:"],"~$small-worlds-table",["^ ","^1",30,"^2",1,"^5","^A","^6","^7","^8","^7","^9",["^ ","^9","~:map","~:val",["^ ","~:table-name",["^ ","^1",31,"^2",16,"~:end-row",31,"~:end-col",29,"~:tag","~:keyword"],"~:table-data-file",["^ ","^1",32,"^2",21,"^E",32,"^F",94,"^G","~:string"],"~:num-cols",["^ ","^1",35,"^2",14,"^E",35,"^F",16,"^G","~:pos-int"],"~:num-rows",["^ ","^1",36,"^2",14,"^E",36,"^F",16,"^G","^L"],"~:rows-label-path",["^ ","^1",37,"^2",21,"^E",37,"^F",59,"^G","~:vector"],"~:cols-label-path",["^ ","^1",38,"^2",21,"^E",38,"^F",59,"^G","^O"],"~:stats-path",["^ ","^1",39,"^2",16,"^E",39,"^F",57,"^G","^O"]]]],"~:filename","/Users/zhangzixiong/Desktop/Workspace/Github/examples/clojure-examples/snippets/clojure-by-example/src/examples/fun/inspect_nasa_planets.clj","~$small-worlds",["^ ","^1",200,"^2",1,"^3",["^4",[0]],"^5","^S","^6","^7","^8","^7","^9","^:"],"~$cleanup-table-data",["^ ","^1",95,"^2",1,"^5","^T","^6","^7","^8","^7"],"~$planets-rel-earth",["^ ","^1",191,"^2",1,"^3",["^4",[0]],"^5","^U","^6","^7","^8","^7","^9","^:"],"~$planet-properties",["^ ","^1",181,"^2",1,"^3",["^4",[1]],"^5","^V","^6","^7","^8","^7","^9","^:"],"~$planets-to-earth-ratios-table",["^ ","^1",20,"^2",1,"^5","^W","^6","^7","^8","^7","^9",["^ ","^9","^B","^C",["^ ","^D",["^ ","^1",21,"^2",16,"^E",21,"^F",39,"^G","^H"],"^I",["^ ","^1",22,"^2",21,"^E",22,"^F",71,"^G","^J"],"^K",["^ ","^1",23,"^2",14,"^E",23,"^F",16,"^G","^L"],"^M",["^ ","^1",24,"^2",14,"^E",24,"^F",16,"^G","^L"],"^N",["^ ","^1",25,"^2",21,"^E",25,"^F",59,"^G","^O"],"^P",["^ ","^1",26,"^2",21,"^E",26,"^F",59,"^G","^O"],"^Q",["^ ","^1",27,"^2",16,"^E",27,"^F",57,"^G","^O"]]]],"~$massage-table-info",["^ ","^1",63,"^2",1,"^3",["^4",[1]],"^5","^X","^6","^7","^8","^7","^<",["^ ","~i1",["^ ","^=","~:associative","^?","[{:keys [table-data-file num-cols num-rows] :as table-info}]"]],"^9","^:"]]
--------------------------------------------------------------------------------
/.clj-kondo/.cache/v1/clj/examples.ex04-api-design.transit.json:
--------------------------------------------------------------------------------
1 | ["^ ","~$surface-temp-tolerable?-refactored",["^ ","~:row",283,"~:col",1,"~:fixed-arities",["~#set",[1]],"~:name","^0","~:ns","~$examples.ex04-api-design","~:top-ns","^7","~:type","~:fn"],"~$co2-tolerable?",["^ ","^1",244,"^2",1,"^3",["^4",[1]],"^5","^;","^6","^7","^8","^7","~:arities",["^ ","~i1",["^ ","~:ret",["^4",["~:nil","~:boolean"]],"~:arglist-str","[planet]"]],"^9","^:"],"~$lower-bound",["^ ","^1",75,"^2",1,"^3",["^4",[1]],"^5","^A","^6","^7","^8","^7","^9","^:"],"~$surface-temp-tolerable?-refactored-v2",["^ ","^1",288,"^2",1,"^3",["^4",[1]],"^5","^B","^6","^7","^8","^7","^<",["^ ","~i1",["^ ","^=","~:symbol","^@","[{{:keys [low high]} :surface-temp-deg-c :as planet}]"]],"^9","^:"],"~:filename","/Users/zhangzixiong/Desktop/Workspace/Github/examples/clojure-examples/snippets/clojure-by-example/src/examples/ex04_api_design.clj","~$tolerances",["^ ","^1",69,"^2",1,"^5","^E","^6","^7","^8","^7","^9",["^ ","^9","~:map","~:val",["^ ","~:co2",["^ ","^1",71,"^2",24,"~:end-row",71,"~:end-col",46,"~:tag",["^ ","^9","^F","^G",["^ ","~:low",["^ ","^1",71,"^2",30,"^I",71,"^J",33,"^K","~:double"],"~:high",["^ ","^1",71,"^2",42,"^I",71,"^J",45,"^K","^M"]]]],"~:gravity",["^ ","^1",72,"^2",24,"^I",72,"^J",46,"^K",["^ ","^9","^F","^G",["^ ","^L",["^ ","^1",72,"^2",30,"^I",72,"^J",33,"^K","^M"],"^N",["^ ","^1",72,"^2",42,"^I",72,"^J",45,"^K","^M"]]]],"~:surface-temp-deg-c",["^ ","^1",73,"^2",24,"^I",73,"^J",45,"^K",["^ ","^9","^F","^G",["^ ","^L",["^ ","^1",73,"^2",30,"^I",73,"^J",34,"^K","~:neg-int"],"^N",["^ ","^1",73,"^2",42,"^I",73,"^J",44,"^K","~:pos-int"]]]]]]],"~$planet-names",["^ ","^1",147,"^2",1,"^5","^S","^6","^7","^8","^7","^9","~:seq"],"~$upper-bound",["^ ","^1",79,"^2",1,"^3",["^4",[1]],"^5","^U","^6","^7","^8","^7","^9","^:"],"~$add-useless-trivia",["^ ","^1",196,"^2",1,"^3",["^4",[1]],"^5","^V","^6","^7","^8","^7","^<",["^ ","~i1",["^ ","^=","~:associative","^@","[{:keys [pname mass] :as planet}]"]],"^9","^:"],"~$atmosphere-present?-refactored",["^ ","^1",234,"^2",1,"^3",["^4",[1]],"^5","^X","^6","^7","^8","^7","^9","^:"],"~$add-any-numbers",["^ ","^1",39,"^2",1,"~:varargs-min-arity",0,"^5","^Y","^6","^7","^8","^7","^9","^:"],"~$co2-tolerable?-refactored",["^ ","^1",254,"^2",1,"^3",["^4",[1]],"^5","^[","^6","^7","^8","^7","^9","^:"],"~$lower-bound-v2",["^ ","^1",86,"^2",1,"^3",["^4",[1,2]],"^5","^10","^6","^7","^8","^7","^<",["^ ","~i2",["^ ","^=","^C","^@","[FIX1 FIX2]"]],"^9","^:"],"~$surface-temp-tolerable?",["^ ","^1",271,"^2",1,"^3",["^4",[1]],"^5","^11","^6","^7","^8","^7","^<",["^ ","~i1",["^ ","^=",["^4",["^>","^?"]],"^@","[planet]"]],"^9","^:"],"~$atmosphere-present?",["^ ","^1",229,"^2",1,"^3",["^4",[1]],"^5","^12","^6","^7","^8","^7","^<",["^ ","~i1",["^ ","^=","^?","^@","[planet]"]],"^9","^:"],"~$add-upto-three-nums",["^ ","^1",22,"^2",1,"^3",["^4",[0,1,3,2]],"^5","^13","^6","^7","^8","^7","^<",["^ ","~i0",["^ ","^=","~:nat-int","^@","[]"],"~i2",["^ ","^=","~:number","^@","[x y]"],"~i3",["^ ","^=","^15","^@","[x y z]"]],"^9","^:"]]
--------------------------------------------------------------------------------
/tutorials/clojure-by-example/src/examples/fun/workshop_fmt.clj:
--------------------------------------------------------------------------------
1 | (ns examples.fun.workshop-fmt
2 | (:require [clojure.edn :as edn]
3 | [clojure.java.io :as io]
4 | [rewrite-clj.zip :as z])
5 | (:import java.io.PushbackReader))
6 |
7 | (def relative-src-path "src/clojure_by_example/")
8 | (def relative-dest-path (str relative-src-path "workshop/"))
9 | (def workshop-file-pattern (re-pattern "ex.*.clj"))
10 |
11 |
12 | (defn elide-if-comment
13 | [zloc]
14 | (if (= (z/value zloc) 'comment)
15 | (-> zloc z/up z/remove)
16 | zloc))
17 |
18 |
19 | (defn elide-comment-forms
20 | [zloc]
21 | (if (z/end? zloc)
22 | zloc
23 | (recur (-> zloc elide-if-comment z/next))))
24 |
25 |
26 | (defn workshop-files!
27 | [sourcedir file-pattern]
28 | (->> (io/file sourcedir)
29 | .listFiles
30 | (filter #(not (.isDirectory %)))
31 | (map #(.getName %))
32 | (filterv (fnil #(re-find file-pattern %) ""))))
33 |
34 |
35 | (defn spit-root!
36 | [zloc outfile]
37 | (with-open [w (io/writer outfile :encoding "UTF-8")]
38 | (z/print-root zloc w)))
39 |
40 |
41 | (defn prep-workshop-code!
42 | ([infile outfile]
43 | (-> (z/of-file infile)
44 | elide-comment-forms
45 | (spit-root! outfile)))
46 | ([infile indir outdir]
47 | (prep-workshop-code!
48 | (str indir infile)
49 | (str outdir infile))))
50 |
51 |
52 | (comment
53 | ;; Try one...
54 | (prep-workshop-code! "ex06_full_functional_firepower.clj"
55 | relative-src-path
56 | relative-dest-path)
57 |
58 | ;; Review output using:
59 | ;; ls -1 | grep ex | xargs -I {} diff -s {} "workshop/"{}
60 | (doseq [f (sort (workshop-files! relative-src-path
61 | workshop-file-pattern))]
62 | (prep-workshop-code! f
63 | relative-src-path
64 | relative-dest-path))
65 | )
66 |
67 |
68 | (comment
69 | ;; Experiment with file as EDN
70 | (defn read-forms [file]
71 | ;; https://stackoverflow.com/questions/39976680/reading-another-clojure-program-as-a-list-of-s-expressions
72 | (let [rdr (-> file io/file io/reader PushbackReader.)
73 | sentinel (Object.)]
74 | (loop [forms []]
75 | (let [form (edn/read {:eof sentinel} rdr)]
76 | (if (= sentinel form)
77 | forms
78 | (recur (conj forms form)))))))
79 | )
80 |
81 | (comment
82 | ;; Experiments with zippers
83 |
84 | ((comp z/child-sexprs z/down) (z/of-file "foobar.clj"))
85 |
86 | (spit-root!
87 | (z/prewalk (z/of-file "foobar.clj")
88 | #(= (z/value %) 'comment)
89 | z/remove)
90 | "foobar-cleaned.clj")
91 |
92 |
93 | (let [zloc (z/of-file (str sourcedir "foobar.clj"))
94 | outfile (str sourcedir "foobar-cleaned.clj")]
95 | (with-open [w (clojure.java.io/writer outfile :encoding "UTF-8")]
96 | (loop [znodes zloc]
97 | (if (z/end? znodes)
98 | (z/print-root znodes w)
99 | (recur (if (= (z/value znodes) 'comment) ; for fanciness, this could be a comment macro by another name, like `extra-explanation'
100 | ((comp z/next z/remove z/up) znodes)
101 | (z/next znodes)))))))
102 | )
103 |
--------------------------------------------------------------------------------
/web/echo-server/echo-server.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/.clj-kondo/.cache/v1/clj/examples.ex03-data-and-functions.transit.json:
--------------------------------------------------------------------------------
1 | ["^ ","~$colonisable?",["^ ","~:row",281,"~:col",1,"~:fixed-arities",["~#set",[1]],"~:name","^0","~:ns","~$examples.ex03-data-and-functions","~:top-ns","^7","~:type","~:fn"],"~$starfleet-mission-configurations",["^ ","^1",91,"^2",1,"^5","^;","^6","^7","^8","^7","^9",["^ ","^9","~:map","~:val",["^ ","~:inhabit",["^ ","^1",97,"^2",13,"~:end-row",99,"~:end-col",25,"~:tag",["^ ","^9","^<","^=",["^ ","~:starships",["^ ","^1",97,"^2",25,"^?",97,"^@",26,"^A","~:pos-int"],"~:battle-cruisers",["^ ","^1",97,"^2",45,"^?",97,"^@",46,"^A","^C"],"~:orbiters",["^ ","^1",98,"^2",24,"^?",98,"^@",25,"^A","^C"],"~:cargo-ships",["^ ","^1",98,"^2",41,"^?",98,"^@",42,"^A","^C"],"~:probes",["^ ","^1",99,"^2",22,"^?",99,"^@",24,"^A","^C"]]]],"~:colonise",["^ ","^1",101,"^2",14,"^?",101,"^@",40,"^A",["^ ","^9","^<","^=",["^ ","^B",["^ ","^1",101,"^2",26,"^?",101,"^@",27,"^A","^C"],"^G",["^ ","^1",101,"^2",37,"^?",101,"^@",39,"^A","^C"]]]],"~:probe",["^ ","^1",103,"^2",11,"^?",103,"^@",37,"^A",["^ ","^9","^<","^=",["^ ","^E",["^ ","^1",103,"^2",22,"^?",103,"^@",23,"^A","^C"],"^G",["^ ","^1",103,"^2",33,"^?",103,"^@",36,"^A","^C"]]]],"~:observe",["^ ","^1",105,"^2",13,"^?",105,"^@",38,"^A",["^ ","^9","^<","^=",["^ ","^E",["^ ","^1",105,"^2",24,"^?",105,"^@",25,"^A","^C"],"^G",["^ ","^1",105,"^2",35,"^?",105,"^@",37,"^A","^C"]]]]]]],"~$minimal-good-conditions",["^ ","^1",220,"^2",1,"^5","^K","^6","^7","^8","^7","^9","~:vector"],"~$co2-tolerable?",["^ ","^1",148,"^2",1,"^3",["^4",[1]],"^5","^M","^6","^7","^8","^7","~:arities",["^ ","~i1",["^ ","~:ret",["^4",["~:nil","~:boolean"]],"~:arglist-str","[planet]"]],"^9","^:"],"~$habitable?",["^ ","^1",265,"^2",1,"^3",["^4",[1]],"^5","^S","^6","^7","^8","^7","^9","^:"],"~$planet-meets-all-conditions?",["^ ","^1",253,"^2",1,"^3",["^4",[2]],"^5","^T","^6","^7","^8","^7","^N",["^ ","~i2",["^ ","^O","^Q","^R","[conditions planet]"]],"^9","^:"],"~$issue-mission-directive",["^ ","^1",318,"^2",1,"^3",["^4",[1]],"^5","^U","^6","^7","^8","^7","^N",["^ ","~i1",["^ ","^O",["^4",["~:keyword"]],"^R","[planet]"]],"^9","^:"],"~$observe-only?",["^ ","^1",297,"^2",1,"^3",["^4",[1]],"^5","^W","^6","^7","^8","^7","^9","^:"],"~$planet-meets-any-one-condition?",["^ ","^1",249,"^2",1,"^5","^X","^6","^7","^8","^7","^9","^:"],"~$fatal-conditions",["^ ","^1",228,"^2",1,"^5","^Y","^6","^7","^8","^7","^9","^L"],"~$lower-bound",["^ ","^1",130,"^2",1,"^3",["^4",[1]],"^5","^Z","^6","^7","^8","^7","^9","^:"],"~$poison-gas?",["^ ","^1",125,"^2",1,"^5","^[","^6","^7","^8","^7","^9","~:set"],"~$air-too-poisonous?",["^ ","^1",187,"^2",1,"^3",["^4",[1]],"^5","^11","^6","^7","^8","^7","^N",["^ ","~i1",["^ ","^O","^Q","^R","[planet]"]],"^9","^:"],"~:filename","/Users/zhangzixiong/Desktop/Workspace/Github/examples/clojure-examples/snippets/clojure-by-example/src/examples/ex03_data_and_functions.clj","~$conditions-met",["^ ","^1",235,"^2",1,"^3",["^4",[2]],"^5","^13","^6","^7","^8","^7","^N",["^ ","~i2",["^ ","^O","~:seq","^R","[condition-fns planet]"]],"^9","^:"],"~$tolerances",["^ ","^1",118,"^2",1,"^5","^15","^6","^7","^8","^7","^9",["^ ","^9","^<","^=",["^ ","~:co2",["^ ","^1",120,"^2",24,"^?",120,"^@",46,"^A",["^ ","^9","^<","^=",["^ ","~:low",["^ ","^1",120,"^2",30,"^?",120,"^@",33,"^A","~:double"],"~:high",["^ ","^1",120,"^2",42,"^?",120,"^@",45,"^A","^18"]]]],"~:gravity",["^ ","^1",121,"^2",24,"^?",121,"^@",46,"^A",["^ ","^9","^<","^=",["^ ","^17",["^ ","^1",121,"^2",30,"^?",121,"^@",33,"^A","^18"],"^19",["^ ","^1",121,"^2",42,"^?",121,"^@",45,"^A","^18"]]]],"~:surface-temp-deg-c",["^ ","^1",122,"^2",24,"^?",122,"^@",45,"^A",["^ ","^9","^<","^=",["^ ","^17",["^ ","^1",122,"^2",30,"^?",122,"^@",34,"^A","~:neg-int"],"^19",["^ ","^1",122,"^2",42,"^?",122,"^@",44,"^A","^C"]]]]]]],"~$gravity-tolerable?",["^ ","^1",161,"^2",1,"^3",["^4",[1]],"^5","^1=","^6","^7","^8","^7","^N",["^ ","~i1",["^ ","^O",["^4",["^P","^Q"]],"^R","[planet]"]],"^9","^:"],"~$upper-bound",["^ ","^1",135,"^2",1,"^3",["^4",[1]],"^5","^1>","^6","^7","^8","^7","^9","^:"],"~$planet-meets-no-condition?",["^ ","^1",244,"^2",1,"^3",["^4",[2]],"^5","^1?","^6","^7","^8","^7","^N",["^ ","~i2",["^ ","^O","^Q","^R","[conditions planet]"]],"^9","^:"],"~$assign-vessels",["^ ","^1",327,"^2",1,"^3",["^4",[1]],"^5","^1@","^6","^7","^8","^7","^N",["^ ","~i1",["^ ","^O","~:associative","^R","[planet]"]],"^9","^:"],"~$surface-temp-tolerable?",["^ ","^1",172,"^2",1,"^3",["^4",[1]],"^5","^1B","^6","^7","^8","^7","^N",["^ ","~i1",["^ ","^O",["^4",["^P","^Q"]],"^R","[planet]"]],"^9","^:"],"~$atmosphere-present?",["^ ","^1",140,"^2",1,"^3",["^4",[1]],"^5","^1C","^6","^7","^8","^7","^N",["^ ","~i1",["^ ","^O","^Q","^R","[planet]"]],"^9","^:"]]
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [![Contributors][contributors-shield]][contributors-url]
2 | [![Forks][forks-shield]][forks-url]
3 | [![Stargazers][stars-shield]][stars-url]
4 | [![Issues][issues-shield]][issues-url]
5 | [![MIT License][license-shield]][license-url]
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | Demo
16 | ·
17 | 更多项目
18 | ·
19 | 参考资料
20 |
21 |
22 |
23 |
24 |
25 | # Introduction
26 |
27 | [](https://example.com)
28 |
29 | Here's a blank template to get started:
30 | **To avoid retyping too much info. Do a search and replace with your text editor for the following:**
31 | `wx-chevalier`, `repo`, `twitter_handle`, `email`
32 |
33 | ## Nav | 导航
34 |
35 | # Getting Started
36 |
37 | To get a local copy up and running follow these simple steps.
38 |
39 | ## Prerequisites
40 |
41 | This is an example of how to list things you need to use the software and how to install them.
42 |
43 | - npm
44 |
45 | ```sh
46 | npm install npm@latest -g
47 | ```
48 |
49 | ## Installation
50 |
51 | 1. Clone the repo
52 |
53 | ```sh
54 | git clone https://github.com/wx-chevalier/repo.git
55 | ```
56 |
57 | 2. Install NPM packages
58 |
59 | ```sh
60 | npm install
61 | ```
62 |
63 |
64 |
65 | ## Usage
66 |
67 | Use this space to show useful examples of how a project can be used. Additional screenshots, code examples and demos work well in this space. You may also link to more resources.
68 |
69 | _For more examples, please refer to the [Documentation](https://example.com)_
70 |
71 | # About
72 |
73 |
74 |
75 | ## Roadmap
76 |
77 | See the [open issues](https://github.com/wx-chevalier/repo/issues) for a list of proposed features (and known issues).
78 |
79 |
80 |
81 | ## Contributing
82 |
83 | Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are **greatly appreciated**.
84 |
85 | 1. Fork the Project
86 | 2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`)
87 | 3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`)
88 | 4. Push to the Branch (`git push origin feature/AmazingFeature`)
89 | 5. Open a Pull Request
90 |
91 |
92 |
93 | ## License
94 |
95 | Distributed under the MIT License. See `LICENSE` for more information.
96 |
97 |
98 |
99 | ## Acknowledgements
100 |
101 | - [Awesome-Lists](https://github.com/wx-chevalier/Awesome-Lists): 📚 Guide to Galaxy, curated, worthy and up-to-date links/reading list for ITCS-Coding/Algorithm/SoftwareArchitecture/AI. 💫 ITCS-编程/算法/软件架构/人工智能等领域的文章/书籍/资料/项目链接精选。
102 |
103 | - [Awesome-CS-Books](https://github.com/wx-chevalier/Awesome-CS-Books): :books: Awesome CS Books/Series(.pdf by git lfs) Warehouse for Geeks, ProgrammingLanguage, SoftwareEngineering, Web, AI, ServerSideApplication, Infrastructure, FE etc. :dizzy: 优秀计算机科学与技术领域相关的书籍归档。
104 |
105 | ## Copyright & More | 延伸阅读
106 |
107 | 笔者所有文章遵循[知识共享 署名 - 非商业性使用 - 禁止演绎 4.0 国际许可协议](https://creativecommons.org/licenses/by-nc-nd/4.0/deed.zh),欢迎转载,尊重版权。您还可以前往 [NGTE Books](https://ng-tech.icu/books/) 主页浏览包含知识体系、编程语言、软件工程、模式与架构、Web 与大前端、服务端开发实践与工程架构、分布式基础架构、人工智能与深度学习、产品运营与创业等多类目的书籍列表:
108 |
109 | [](https://ng-tech.icu/books/)
110 |
111 |
112 |
113 |
114 | [contributors-shield]: https://img.shields.io/github/contributors/wx-chevalier/repo.svg?style=flat-square
115 | [contributors-url]: https://github.com/wx-chevalier/repo/graphs/contributors
116 | [forks-shield]: https://img.shields.io/github/forks/wx-chevalier/repo.svg?style=flat-square
117 | [forks-url]: https://github.com/wx-chevalier/repo/network/members
118 | [stars-shield]: https://img.shields.io/github/stars/wx-chevalier/repo.svg?style=flat-square
119 | [stars-url]: https://github.com/wx-chevalier/repo/stargazers
120 | [issues-shield]: https://img.shields.io/github/issues/wx-chevalier/repo.svg?style=flat-square
121 | [issues-url]: https://github.com/wx-chevalier/repo/issues
122 | [license-shield]: https://img.shields.io/github/license/wx-chevalier/repo.svg?style=flat-square
123 | [license-url]: https://github.com/wx-chevalier/repo/blob/master/LICENSE.txt
124 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Documents
7 |
8 |
9 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
34 |
35 |
36 |
|
37 |
38 |
|
39 |
40 |
41 |
42 |
45 |
46 |
49 |
52 |
53 |
86 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
140 |
141 |
142 |
143 |
--------------------------------------------------------------------------------
/tutorials/clojure-by-example/src/examples/ex02_domain_as_data.clj:
--------------------------------------------------------------------------------
1 | (ns examples.ex02-domain-as-data)
2 |
3 | ;; Ex02: LESSON GOAL:
4 | ;; - Model and query things using pure data
5 | ;; - Realize the flexibility and power of collections
6 |
7 |
8 | ;; Our Earth
9 |
10 | ;; "pname" "Earth"
11 | ;; "mass" 1 ; if Earth mass is 1, Jupiter's mass is 317.8 x Earth
12 | ;; "radius" 1 ; if Earth radius is 1, Jupiter's radius is 11.21 x Earth
13 | ;; "moons" 1
14 | ;; "atmosphere" "nitrogen" 78.08
15 | ;; "oxygen" 20.95
16 | ;; "CO2" 0.40
17 | ;; "water-vapour" 0.10
18 | ;; "argon" 0.33
19 | ;; "traces" 0.14
20 |
21 |
22 | ;; Recall: Literal syntax:
23 | ;; - If we just put curly braces in the right places,
24 | ;; we can turn the given table into a Clojure hash-map:
25 |
26 | (def earth
27 | {"pname" "Earth"
28 | "mass" 1
29 | "radius" 1
30 | "moons" 1
31 | "atmosphere" {"nitrogen" 78.08
32 | "oxygen" 20.95
33 | "carbon-dioxide" 0.4
34 | "water-vapour" 0.10
35 | "argon" 0.33
36 | "traces" 0.14}})
37 |
38 | ;; Now we can look up any value using `get`, and `get-in`:
39 |
40 | ;; with `get`
41 | (get earth "pname")
42 |
43 | (get (get earth "atmosphere")
44 | "traces")
45 |
46 |
47 | ;; more conveniently, with `get-in`
48 | (get-in earth ["pname"])
49 |
50 | (get-in earth ["atmosphere" "traces"])
51 | ;; '--> imagine this as a "path" to the value
52 |
53 |
54 |
55 | ;; Alternatively, we can model the earth this way,
56 | ;; using keywords as keys, to great benefit:
57 | (def earth-alt
58 | {:pname "Earth"
59 | :mass 1
60 | :radius 1
61 | :moons 1
62 | :atmosphere {:nitrogen 78.08
63 | :oxygen 20.95
64 | :carbon-dioxide 0.4
65 | :water-vapour 0.10
66 | :argon 0.33
67 | :traces 0.14}})
68 |
69 | ;; EXERCISE
70 | ;; `get` and `get-in` work as expected
71 | ;; - Use `get` to extract :traces from `earth-alt`'s atmosphere
72 | ;; - The use `get-in` to do the same
73 |
74 | #_(get 'FIX
75 | 'FIX)
76 |
77 | #_(get-in 'FIX 'FIX)
78 |
79 |
80 | ;; BUT, unlike plain old strings, keywords also behave as
81 | ;; _functions_ of hash-maps, and can look themselves up
82 | ;; in any given hash-map.
83 |
84 | ;; ("pname" earth) ; Will FAIL!
85 |
86 | (:pname earth-alt) ; Works!
87 |
88 |
89 | ;; EXERCISE
90 | ;; Extract `:argon` from the `:atmosphere` of `earth-alt`
91 |
92 | ('FIX ('FIX earth-alt))
93 |
94 |
95 | ;; Which means we can use keywords in this manner:
96 |
97 | (def planets
98 | [{:pname "Mercury" :moons 0 :mass 0.0533}
99 | {:pname "Venus" :moons 0 :mass 0.815}
100 | {:pname "Earth" :moons 1 :mass 1}
101 | {:pname "Mars" :moons 2 :mass 0.107}])
102 |
103 |
104 | ;; Instead of having to write functions to query planets:
105 | (map (fn [p] (get p :pname))
106 | planets)
107 |
108 | ;; We can directly use keywords as functions:
109 | (map :pname
110 | planets)
111 |
112 |
113 | ;; EXERCISE
114 | ;; `filter` out planets with less `:mass` than the Earth
115 |
116 | (defn less-mass-than-earth?
117 | [planet]
118 | (< ('FIX planet) 1))
119 |
120 | ('FIX 'FIX 'FIX)
121 |
122 |
123 | ;; EXERCISE
124 | ;; Recall how to use `filter`, `map`, and `reduce`:
125 | (filter even? [1 2 3 4])
126 | (map inc [1 2 3 4])
127 | (reduce + 0 [1 2 3 4])
128 | ;; Use these to compute the total `:mass` of planets
129 | ;; having less mass than the Earth.
130 |
131 |
132 |
133 | ;; Maps, Vectors, and Sets also behave like functions!
134 | ;; - We don't normally use maps and vector in the function
135 | ;; position to perform lookups (there are a few problems
136 | ;; with doing so), but we often use _well-defined_ sets as
137 | ;; predicate functions, to test for set membership.
138 |
139 | ;; Maps can "self-look-up" keys
140 |
141 | ({:a "a", :b "b"} :a)
142 |
143 | ;; Vectors can "self-look-up" by index position
144 |
145 | (["a" "b" "c"] 0)
146 |
147 | ;; Sets can self-test set membership
148 |
149 | (#{"a" "b" "c"} "b") ; truthy: return set member if it exists
150 | (#{"a" "b" "c"} "boo") ; falsey: return `nil` if it doesn't
151 |
152 | ;; Lists do NOT behave like functions
153 |
154 | #_('("a" "b" "c") 0) ; FAIL
155 |
156 |
157 | ;; EXERCISE
158 | ;; Define a predicate `poison-gas?` which returns the
159 | ;; poison gas if it belongs to a set of known poison gases,
160 | ;; or `nil` (falsey) otherwise. These are some known poison gases:
161 | :carbon-monoxide, :chlorine, :helium
162 | :sulphur-dioxide, :hydrogen-chloride
163 |
164 |
165 | (def poison-gas?
166 | "Does the given gas belong to a set of known poison gases?"
167 | 'FIX)
168 |
169 | (poison-gas? :chlorine) ; truthy
170 | (poison-gas? :oxygen) ; falsey
171 |
172 |
173 | ;; Collections are "open", i.e. very flexible
174 | ;; - We can make collections out of almost anything
175 |
176 | ;; Recall:
177 | (def a-bunch-of-values
178 | [nil, false, ; falsey
179 | 42, :a, "foo", true, ; truthy
180 | {:a 1, :b 2}, [1 2 3 4], ; truthy
181 | '(), {}, [], ""]) ; truthy
182 |
183 | (map boolean a-bunch-of-values)
184 |
185 |
186 | ;; And since functions are values too, we can potentially use
187 | ;; collections of functions like this:
188 | (map (fn [f] (f 42))
189 | [str identity inc dec (fn [x] x)])
190 |
191 |
192 | ;; Domain Modeling in Clojure
193 | ;; - We use the flexibility of collections, to model
194 | ;; real-world objects and logic as we please
195 |
196 |
197 | ;; Predicates and operations
198 | {:number-checks [even? pos? integer? (fn [x] (> x 42))]
199 | :number-ops [str identity inc dec (fn [x] x)]}
200 |
201 |
202 | ;; A data table:
203 | [[:name :age :country]
204 | ["Foo" 10 "India"]
205 | ["Bar" 21 "Australia"]
206 | ["Baz" 18 "Turkey"]
207 | ["Qux" 42 "Chile"]]
208 |
209 |
210 | ;; HTML (ref: Hiccup templates)
211 | [:div {:class "wow-list"}
212 | [:ul (map (fn [x] [:li x])
213 | [1 2 3 4])]]
214 |
215 |
216 | ;; Musical patterns (ref: github.com/ssrihari/ragavardhini)
217 | {:arohanam [:s :r3 :g3 :m1 :p :d1 :n2 :s.],
218 | :avarohanam [:s. :n2 :d1 :p :m1 :g3 :r3 :s]}
219 |
220 |
221 | ;; DB queries (ref: Datomic)
222 | #_[:find ?name ?duration
223 | :where [?e :artist/name "The Beatles"]
224 | [?track :track/artists ?e]
225 | [?track :track/name ?name]
226 | [?track :track/duration ?duration]]
227 |
228 |
229 | ;; Starfleet mission configurations
230 | {:inhabit {:starships 5, :battle-cruisers 5,
231 | :orbiters 5, :cargo-ships 5,
232 | :probes 30}
233 | :colonise {:starships 1, :probes 50}
234 | :probe {:orbiters 1, :probes 100}
235 | :observe {:orbiters 1, :probes 10}}
236 |
237 |
238 | ;; Only limited by your imagination!
239 |
240 | ;;
241 | ;; 4clojure Drills: Problems you could try now.
242 | ;;
243 | ;; - #protip: Write the solutions as proper named functions in your code base,
244 | ;; without code-golfing or hacks. Then translate to anonymous function form
245 | ;; that 4clojure requires.
246 | ;;
247 | (comment
248 | (map (fn [problem-no] (str "https://4clojure.oxal.org/#/problem/"
249 | problem-no))
250 | [17, 18, 57, 71
251 | 134, 27, 26, 39]))
252 |
--------------------------------------------------------------------------------
/tutorials/clojure-by-example/src/examples/ex07_boldly_go.clj:
--------------------------------------------------------------------------------
1 | (ns examples.ex07-boldly-go)
2 |
3 |
4 | ;; EX07: Lesson Goals
5 | ;;
6 | ;; - Quickly see how to start and architect your own project.
7 | ;; - namespaces, dependencies, project structuring etc...
8 | ;;
9 | ;; - To be able to run your project as a binary (jar) like this:
10 | ;;
11 | ;; java -jar ./path/to/the_library_jarfile.jar "arg1" "arg2" "arg3"
12 |
13 |
14 |
15 | ;; Your First Clojure Library
16 | ;; - Let's turn code from ex06 into a library for planetary exploration.
17 | ;; - Follow the procedure below, step by step.
18 | ;;
19 | ;;
20 | ;; * Use leiningen to create a new project skeleton.
21 | ;;
22 | ;; - Open a terminal session and execute:
23 | ;;
24 | ;; lein new planet_coloniser
25 | ;;
26 | ;;
27 | ;; * Open the directory in your IDE and observe its structure.
28 | ;;
29 | ;;
30 | ;; * Create a `utils` directory in which to put I/O utility functions.
31 | ;; (Putting utility functions in `utils` is only a convention,
32 | ;; not a rule.)
33 | ;;
34 | ;; - Terminal:
35 | ;; mkdir src/planet_coloniser/utils
36 | ;;
37 | ;; - Or, in your IDE:
38 | ;; - right-click on src/planet_coloniser, and create new folder
39 | ;;
40 | ;;
41 | ;; * Inside this new `utils` directory, create two new files:
42 | ;; - `ingest.clj` and
43 | ;; - `export.clj`
44 | ;;
45 | ;; - Again, you can right-click on your `utils` dir in your IDE,
46 | ;; and create New File from the pop-up menu.
47 | ;;
48 | ;;
49 | ;; * Update `ingest.clj` with ingest utility functions.
50 | ;;
51 | ;; - Open the file and add this "ns declaration" at the top:
52 | ;;
53 | ;; (ns planet-coloniser.utils.ingest)
54 | ;;
55 | ;; - Observe the dir name is planet_coloniser, but the ns
56 | ;; declaration has planet-coloniser. This is the convention:
57 | ;; - hyphens separate words in ns names
58 | ;; - dots separate directories and files in ns names
59 | ;; - underscores from dir or file names become hyphens in ns names
60 | ;; - and ns names are all lower case
61 | ;;
62 | ;; - Copy-paste the "input" function definitions from ex06,
63 | ;; below the ns declaration.
64 | ;;
65 | ;;
66 | ;; * Update `ingest.clj`, and project, for external dependency
67 | ;;
68 | ;; - `ingest` uses `clojure.data.json`, which is an external
69 | ;; dependency that we have to specify explicitly.
70 | ;;
71 | ;; - Inside `project.clj`, update :dependencies value to look like:
72 | ;;
73 | ;; :dependencies [[org.clojure/clojure "1.10.0" ; latest as of 01 Jan 2019
74 | ;; [org.clojure/data.json "0.2.6"]] ; add for `ingest`
75 | ;;
76 | ;; - Inside `injest.clj`, update the ns declaration to look like:
77 | ;;
78 | ;; (ns planet-coloniser.utils.ingest
79 | ;; (:require [clojure.data.json :as json]
80 | ;; [clojure.java.io :as io]))
81 | ;;
82 | ;;
83 | ;; * Update `export.clj`. Open the file and:
84 | ;;
85 | ;; - Add the appropriate "ns declaration" at the top
86 | ;;
87 | ;; - Copy-paste only the `write-out-json-file` function here.
88 | ;;
89 | ;; - Later, we will port code from the other function to another file.
90 | ;;
91 | ;; - Also ensure, the ns form looks like this:
92 | ;;
93 | ;; (ns planet-coloniser.utils.ingest
94 | ;; (:require [clojure.data.json :as json]
95 | ;; [clojure.java.io :as io]))
96 | ;;
97 | ;;
98 | ;; * Create `sensor_processor.clj`, for our core "pure" logic:
99 | ;;
100 | ;; - Create it under `src/planet_coloniser/`
101 | ;;
102 | ;; - Add the appropriate ns declaration
103 | ;;
104 | ;; - Copy-paste all the pure functions in there
105 | ;;
106 | ;; - Update the ns form to also require clojure.walk
107 | ;;
108 | ;;
109 | ;; * Update `src/planet_coloniser/core.clj`
110 | ;; - This will contain the entry point for the outside world,
111 | ;; into our planet processor.
112 | ;;
113 | ;; - Delete the dummy function from the namespace
114 | ;;
115 | ;; - Update the `ns` declaration to look like this:
116 | ;;
117 | ;; (ns planet-coloniser.core
118 | ;; (:gen-class) ; add this, and the :require expression below:
119 | ;; (:require [planet-coloniser.sensor-processor :as sensproc]
120 | ;; [planet-coloniser.utils.ingest :as ingest]
121 | ;; [planet-coloniser.utils.export :as export]))
122 | ;;
123 | ;; - Copy `ingest-export-sensor-data!` from ex06
124 | ;;
125 | ;; - Rename it to `-main`.
126 | ;;
127 | ;; - Now, make the body of `-main` look like the function below:
128 | ;; - notice prefixes to functions, like export/, ingest/, sensproc/
129 | ;; - Why do we do this?
130 | ;;
131 | ;; (defn -main
132 | ;; [data-dir source-data-files dest-data-file]
133 | ;; (let [source-data-files (ingest/ingest-json-file! data-dir
134 | ;; source-data-files)
135 | ;; export-as-json (partial export/write-out-json-file!
136 | ;; data-dir
137 | ;; dest-data-file)]
138 | ;; (export-as-json
139 | ;; (sensproc/denormalise-planetary-data
140 | ;; (ingest/gather-all-sensor-data! data-dir
141 | ;; source-data-files)))))
142 | ;;
143 | ;;
144 | ;; * Let's bring in sensor data, for convenience:
145 | ;; - Copy over `sensor_data` directory from clojure-by-example.
146 | ;; - From:
147 | ;; /Path/To/clojure-by-example/resources/sensor_data/
148 | ;; - To:
149 | ;; /Path/To/planet_coloniser/resources/sensor_data/
150 | ;;
151 | ;;
152 | ;; * In the new `sensor_data` directory, create a new JSON file:
153 | ;;
154 | ;; - call it `sensor_data_files.json`
155 | ;;
156 | ;; - add the following JSON to it:
157 | ;;
158 | ;; {"planets":"planet_detector.json",
159 | ;; "moons":"moon_detector.json",
160 | ;; "atmosphere":"atmospheric_detector.json"}
161 | ;;
162 | ;;
163 | ;; * Let's make the project runnable:
164 | ;;
165 | ;; - Update `project.clj` to specify entry point.
166 | ;;
167 | ;; - After :dependencies, add the location of the main function:
168 | ;;
169 | ;; :main planet-coloniser.core
170 | ;;
171 | ;;
172 | ;; * Check if the project has indeed become runnable:
173 | ;;
174 | ;; - In the terminal, cd to the root directory of your
175 | ;; `planet_coloniser` project.
176 | ;;
177 | ;; - Use leiningen to run the library:
178 | ;;
179 | ;; lein run "resources/sensor_data/" "sensor_data_files.json" "lein_out.json"
180 | ;;
181 | ;; - Did that work?
182 | ;; - Check resources/lein_out.json
183 | ;;
184 | ;;
185 | ;; * Let's bump our project version to `0.1.0` :-D
186 | ;; - In project.clj, delete `-SNAPSHOT` from the project version
187 | ;; (see it at the top of the project definition)
188 | ;;
189 | ;;
190 | ;; * Finally, let's prep the project for building a java executable.
191 | ;; - Update `project.clj` for Ahead-Of-Time compilation,
192 | ;; required in order to produce a standalone Java executable jar.
193 | ;;
194 | ;; - Below :main, add this:
195 | ;;
196 | ;; :aot :all
197 | ;;
198 | ;; - Use leiningen to Build the jar:
199 | ;; - In your terminal, cd into the root of your project,
200 | ;; and execute:
201 | ;;
202 | ;; lein uberjar
203 | ;;
204 | ;; - Observe the build output in your terminal.
205 | ;;
206 | ;; - Do you see two jar files created under `planet_coloniser/target`?
207 | ;;
208 | ;;
209 | ;; * Now run the "standalone" jar as:
210 | ;;
211 | ;; java -jar target/planet_coloniser-0.1.0-standalone.jar "resources/sensor_data/" "sensor_data_files.json" "jar_out.json"
212 | ;;
213 | ;; - Did that work?
214 | ;; - Check the output file
215 | ;;
216 | ;;
217 | ;; * If you've reached this far...
218 | ;; - Congratulations, you just built a brand new Clojure project
219 | ;; from scratch!
220 | ;;
221 | ;;
222 |
223 |
224 | ;; HOMEWORK:
225 | ;;
226 | ;; * Why did we have to do all this?
227 | ;; Ben Vandgrift has a nice explanation at:
228 | ;; "Clojure: 'Hello World' from the Command Line"
229 | ;; http://ben.vandgrift.com/2013/03/13/clojure-hello-world.html
230 |
--------------------------------------------------------------------------------
/tutorials/clojure-by-example/src/examples/ex00_introduction.clj:
--------------------------------------------------------------------------------
1 | (ns examples.ex00-introduction)
2 |
3 |
4 | ;; IMPORTANT:
5 | ;; - The README file explains why this project exists.
6 | ;; - Begin in this "ex00..." file, and work through it step by step.
7 | ;; - Once you are done with "ex00...", open the next file and repeat.
8 | ;; - Keep going this way, until you have worked through all the files.
9 | ;; - Once done with a file, read the recap and try any additional
10 | ;; problem sets listed there, to get more practice.
11 |
12 | ;; EX00: LESSON GOAL:
13 | ;; - Drill some Clojure basics, required for the sections
14 | ;; that follow (and generally, to help follow code
15 | ;; in the wild)
16 | ;; - Familiarize one's eyes with Clojure syntax
17 | ;; - Understand Clojure's evaluation model
18 | ;; - Start using an interactive development workflow
19 | ;; right away --- this is what it means to be a
20 | ;; "Dynamic" programming language (not to be confused
21 | ;; with dynamically typed languages.)
22 |
23 |
24 | ;; All Clojure code is composed of "expressions":
25 | ;; - And, all Clojure expressions evaluate to a value.
26 |
27 | ;; - "Atomic" literals:
28 | "hello" ; strings
29 | :hello ; keywords
30 | \h \e \l \l \o ; characters
31 | 'hello ; symbols
32 | 42 ; numbers
33 | 22/7 ; fractional numbers
34 | nil ; yes, nil is a value
35 |
36 | ;; - Collection literals:
37 | [1 2 3 4 5] ; a vector
38 | {:a 1 :b 2} ; a hash-map (key-value pairs)
39 | #{1 2 3 4 5} ; a hash-set
40 | '(1 2 3 4 5) ; a list
41 |
42 | ;; - "Built-in" functions:
43 | + ; addition
44 | map ; map over a collection
45 | filter ; filter from a collection
46 | reduce ; transform a collection
47 |
48 | ;; - "Symbolic" expressions (or "s"-expression or s-expr)
49 |
50 | (+ 1 2) ; a simple s-expr
51 |
52 | (+ (+ 1 2) (+ 1 2)) ; an s-expr of nested s-exprs
53 |
54 | (+ (+ (+ 1 2) (+ 1 2))
55 | (+ (+ 1 2) (+ 1 2))) ; an even more nested s-expr
56 |
57 | (defn same
58 | [x]
59 | x) ; function definitions are also s-exprs
60 |
61 | ;; Namespaces:
62 | ;;
63 | ;; - are how we organize and/or modularise code
64 | ;; - All Clojure code is defined and evaluated within namespaces
65 |
66 |
67 | ;; EXERCISE:
68 | ;; Evaluate the following expressions and see what you get.
69 | ;; - First, type the expression in the REPL
70 | ;; - Next, evaluate them straight from your codebase
71 |
72 | map ; is defined in the `clojure.core` ns (namespace)
73 |
74 | same ; is defined in the current ns
75 |
76 | #_(ns-name *ns*) ; What's the current ns?
77 |
78 | (comment
79 | ;; PROTIP:
80 | ;;
81 | ;; Your IDE or text editor would have a convenient shortcut to
82 | ;; evaluate any Clojure expression right from your codebase.
83 | ;;
84 | ;; Some editors allow you to "evaluate in-line", some would
85 | ;; tell you to "send to the REPL". Consult the documentation
86 | ;; that accompanies your editor's Clojure plugin, to learn
87 | ;; how to do this.
88 | ;;
89 | ;; Make a habit of interacting "dynamically" with Clojure
90 | ;; this way, right from inside your codebase; i.e. prefer
91 | ;;_not_ to type things directly into the REPL.
92 | )
93 |
94 |
95 |
96 | ;; Clojure expression syntax rules:
97 |
98 | ;; - Literals:
99 | ;; - Just write them down
100 |
101 | ;; - Collection literals and s-expressions:
102 | ;; - ABC - Always. Be. Closing. :-D
103 | ;; - The Clojure "Reader" (the 'R' part of the R.E.P.L)
104 | ;; expects each open bracket to be accompanied by a
105 | ;; corresponding closing bracket. i.e. all parentheses
106 | ;; must be "balanced".
107 |
108 | ;; [1 2 3] ; OK
109 | ;; [1 2 3 ; FAIL
110 |
111 | ;; {:a 1 :b 2} ; OK
112 | ;; {:a 1 :b 2 ; FAIL
113 |
114 | ;; (+ 1 2) ; OK
115 | ;; (+ 1 2 ; FAIL
116 |
117 | ;; - Indentation, extra spaces, and commas are just for
118 | ;; our reading convenience. Example: all of the following
119 | ;; literal maps represent the same value:
120 |
121 | {:a 1 :b 2}
122 |
123 | {:a 1, :b 2}
124 |
125 | {:a 1,
126 | :b 2}
127 |
128 | {:a 1
129 | :b 2}
130 |
131 | {:a 1
132 | :b
133 | 2}
134 |
135 |
136 |
137 | ;; Clojure Expression Evaluation Rules:
138 |
139 | ;; - Wrap in parentheses to cause evaluation.
140 | ;; The first position is special, and must be
141 | ;; occupied by a function
142 |
143 | (+ 1 2) ; OK
144 | ;; (1 2) ; FAIL, because 1 is not a function
145 |
146 | ;; - Mentally evaluate nested expressions "inside-out".
147 | ;; Usually, all s-expressions--however deeply nested--evaluate
148 | ;; to a return value; a literal, or a collection, or a function,
149 | ;; or some legal object.
150 |
151 | (+ (+ (+ 1 2) (+ 1 2))
152 | (+ (+ 1 2) (+ 1 2)))
153 |
154 | (+ (+ 3 3 )
155 | (+ 3 3 ))
156 |
157 | (+ 6
158 | 6)
159 |
160 | 12
161 |
162 | ;; - _Prevent_ evaluation of s-expr by "quoting" it,
163 | ;; i.e. explicitly marking a list, by prefixing it
164 | ;; with a single quote `'`:
165 |
166 | '(+ 1 2) ; BUT the list will still remain in the evaluation path
167 |
168 | ;; - Leave an s-expression in-line, but remove it from
169 | ;; the evaluation path, by prefixing it with `#_`:
170 |
171 | (+ 1 2 #_(+ 1 2)) ; will evaluate to 3
172 |
173 | ;; - Comment out entirely, by prefixing code with one or more
174 | ;; semicolons, just like in-line comments.
175 |
176 | ;; (+ (+ 1 2)
177 | ;; (+ 1 2)) ; fully commented out
178 |
179 |
180 | ;; EXERCISE:
181 | ;; - Now, why will the following expression fail (throw an exception)?
182 | ;; Make an educated guess, then try it.
183 |
184 | ;; (+ 1 2 '(+ 1 2)) ; un-comment and evaluate; then comment it back
185 |
186 |
187 | (comment
188 | ;; PROTIP:
189 | ;;
190 | ;; The special "#_" syntax is called a "reader macro".
191 | ;;
192 | ;; For now, ignore what that means, just know the effect of
193 | ;; using it. You will see #_ often in code to follow.
194 | ;;
195 | ;; Incidentally, the single quote we used '(to mark a list)
196 | ;; is also a reader macro. Many more specialized reader macros
197 | ;; are available, but don't go there just yet.
198 | )
199 |
200 |
201 |
202 | ;; Why is Clojure a Lisp ("LISt Processing") language?
203 |
204 | '(+ 1 2) ; Recall: this is a Clojure list, that Clojure evaluates
205 | ; as literal data.
206 |
207 | (+ 1 2) ; if we remove the single quote, Clojure treats the same list
208 | ; as an executable list, and tries to evaluate it as code.
209 |
210 |
211 | ;; More generally, Clojure code is written in terms of Clojure's
212 | ;; own data structures. For example:
213 | ;;
214 | ;; Here is a function definition.
215 | (defn hie
216 | [person message]
217 | (str "Hie, " person " : " message))
218 |
219 | ;; What does it look like?
220 | ;; - Let's flatten it into one line for illustrative purposes:
221 |
222 | ;;[1] [2] [3] [4]
223 | (defn hie [person message] (str "Hie, " person " : " message)) ; [5]
224 |
225 | (comment
226 | ;; Here:
227 | ;; - [1] `defn` is a Clojure built-in primitive
228 | ;; - Notice, it's at the 1st position, and
229 | ;; - 2-4 are all arguments to defn
230 | ;; Further:
231 | ;; - [2] is a Clojure symbol, `hie`, which will name the function
232 | ;; - [3] is a Clojure vector of two named arguments
233 | ;; - [4] is a Clojure s-expression, and is treated as the body of
234 | ;; the function definition
235 | ;; - [5] the whole thing itself is a Clojure s-expression!
236 | )
237 |
238 |
239 | ;; RECAP:
240 | ;;
241 | ;; - All Clojure code is a bunch of "expressions"
242 | ;; (literals, collections, s-expressions)
243 | ;;
244 | ;; - All Clojure expressions evaluate to a return value
245 | ;;
246 | ;; - All Clojure code is written in terms of its own data structures
247 | ;;
248 | ;; - All opening braces or parentheses must be matched by closing
249 | ;; braces or parentheses, to create legal Clojure expressions.
250 |
251 | ;; 4clojure Drills: Problems you could try now.
252 | ;;
253 | ;; - With the knowledge you have so far, you can try solving these
254 | ;; problems at 4clojure.com: 1 to 13, and 16, 47, 126, 161, and 162
255 | ;; e.g. https://4clojure.oxal.org/#/problem/1
256 | ;; e.g. https://4clojure.oxal.org/#/problem/16
257 |
--------------------------------------------------------------------------------
/tutorials/clojure-by-example/src/examples/ex05_immutability_and_fp.clj:
--------------------------------------------------------------------------------
1 | (ns examples.ex05-immutability-and-fp)
2 |
3 | ;; Ex05: Lesson Goals
4 | ;; - This section is more conceptual, than exercise-oriented.
5 | ;;
6 | ;; - Set you up with some important ideas, which we will use heavily
7 | ;; in the final section (and in all our Clojure programs)
8 | ;; - All values are immutable by default (and we like it this way)
9 | ;; - What `def` is
10 | ;; - Why you should avoid global defs
11 | ;; - What are "pure functions"?
12 | ;;
13 | ;; - Don't forget to evaluate all s-expressions that interest you,
14 | ;; and also feel free to write and play around with your own ones.
15 |
16 |
17 |
18 | ;; Previously, in Clojure by Example:
19 | ;;
20 | ;; - We either only queried one or more planets,
21 | ;; - Or we checked if values satisfy some "predicate"
22 | ;; - Or we calculated new values using (reduce + ...) etc.
23 | ;; - Or we defined globals (with def), and locals (with let)
24 | ;;
25 | ;; - But we did not really try to modify or change any quantity
26 | ;; or sequence.
27 |
28 |
29 | ;; What if we try to "change" things?
30 |
31 |
32 | (def pi 3.141)
33 |
34 | (+ pi 1) ; add one to pi
35 |
36 | ;; EXERCISE:
37 | ;;
38 | ;; Predict the value of pi:
39 |
40 | pi ; evaluate to confirm
41 |
42 |
43 | ;; Hm, let's try vectors and maps.
44 | ;;
45 | ;; - We can "associate" new key-vals into an existing map
46 | (assoc {:a 1}
47 | :b 2
48 | :c 3)
49 | ;;
50 | ;; - With assoc, we can also update existing key-value pairs
51 | (assoc {:a 1 :b 2}
52 | :b 99)
53 | ;;
54 | ;; - And, finally, we can "dissociate" existing key-vals
55 | (dissoc {:a 1 :b 2 :c 3}
56 | :b
57 | :c)
58 |
59 |
60 | ;; - So suppose we define...
61 |
62 | (def planets [{:pname "Earth" :moons 1}
63 | {:pname "Mars" :moons 2}])
64 |
65 | ;; - Then, maybe, we can `assoc` a new k-v pair into all planets:
66 | ;; - And while we're at it, also dissoc an existing one:
67 | ;;
68 | (map (fn [planet]
69 | (assoc (dissoc planet :moons)
70 | :habitable? true))
71 | planets)
72 |
73 |
74 | ;; EXERCISE:
75 | ;;
76 | ;; Predict the result of filtering by the value of `:habitable?`:
77 |
78 | (filter :habitable? planets)
79 |
80 | planets ; confirm by checking the value of this
81 |
82 |
83 |
84 | ;; WHY IS Clojure DOING THIS TO US???!!!
85 | ;;
86 | ;; Why are we not allowed to mutate these things?
87 | ;;
88 | ;; How will we get _anything_ done in the real world?
89 | ;;
90 | ;; Well, actually, you've _already_ been programming with such
91 | ;; "immutable" values, and it hasn't stopped you from being awesome!
92 | ;;
93 | ;; Now, we just need to learn "The art of fighting, without fighting",
94 | ;; or, how to change the world, _without_ using _things that change_.
95 | ;;
96 | ;; Immutability v/s mutability is a deeply unsettling topic, so
97 | ;; we will park the discussion for now and come back to it in the
98 | ;; next "chapter".
99 | ;;
100 | ;; But first, a few important practicalities.
101 |
102 |
103 | ;; On `def`:
104 | ;;
105 | ;; `def` creates a mutable reference. Technically, it is a way
106 | ;; "to maintain a persistent reference to a changing value".
107 | ;;
108 | ;; Note the difference:
109 | ;; - We can mutate the _reference_, but not the value.
110 | ;; - Values are by definition immutable.
111 | ;;
112 | ;; Warning:
113 | ;; - DO NOT use `def` to _emulate_ mutation.
114 |
115 | ;; Firstly:
116 | ;; - Because you'll cause errors of understanding:
117 |
118 | (def weird-pi 3.141) ; bind weird-pi to 3.141
119 |
120 | (def other-pi weird-pi) ; bind other-pi to the value of weird-pi,
121 | ; which at this point is 3.141
122 |
123 | (def weird-pi 42) ; re-bind weird-pi to some other value
124 |
125 | weird-pi ; changes to 42
126 |
127 | other-pi ; what should this be?
128 |
129 | ;; See the problem?
130 | ;; - We re-bound weird-pi to a new value, but other-pi's binding
131 | ;; remained constant.
132 | ;; - Spread enough re-definitions across your program, and you'll be
133 | ;; in trouble; unable to reason about who's using what version
134 | ;; of the binding.
135 |
136 |
137 | ;; Secondly:
138 | ;; - It's dangerous because re-defining a var alters it globally.
139 | ;; - Why so dangerous?
140 | ;;
141 | ;; Well, compare the following.
142 | ;; - All three are _incorrect_, because pi is wrong.
143 | ;; - But only the third one is actually dangerous.
144 |
145 | (defn scale-by-pi-v1
146 | [n]
147 | (let [pi 42]
148 | (* pi n)))
149 |
150 | (defn scale-by-pi-v2
151 | [n]
152 | (* weird-pi n))
153 |
154 | #_(defn scale-by-pi-v3
155 | [n]
156 | (def pi 42)
157 | (* n pi))
158 |
159 |
160 | ;; Also, remember functions are values?
161 |
162 | (fn [x] x) ; is a value (which shall remain anonymous)
163 |
164 | (defn same
165 | [x]
166 | x) ; `same` is the name of a function.
167 | ; Therefore `same` names a value.
168 |
169 | ;; So what if we:
170 | (def same-same
171 | (fn [x] x)) ; hah!
172 |
173 | ;; As it happens:
174 | ;; - `defn` is really just a convenience wrapper over `def`.
175 | ;; - Because we can't live without defining functions, in Clojure-land
176 |
177 | (macroexpand '(defn same [x] x)) ; yes, it is
178 |
179 | ;; So, truthfully:
180 | ;; - `same` and `same-same` are mutable references to immutable
181 | ;; function definitions.
182 | ;;
183 | ;; Now:
184 | ;; - This mutable binding is very useful during development.
185 | ;; - It lets us interactively improve-and-rebind functions bit by bit.
186 | ;; - Stay in "flow".
187 | ;;
188 | ;; But:
189 | ;; - Imagine the horror of someone or something mutating the definition
190 | ;; of your functions from under you, while your program is running!
191 | ;;
192 | ;; Yet:
193 | ;; - In extremely rare cases, the ability to re-define things in a
194 | ;; live production system can be incredibly useful. Read the
195 | ;; paragraph starting with "The Remote Agent software" on this page:
196 | ;; http://flownet.com/gat/jpl-lisp.html
197 | ;;
198 | ;; Still:
199 | ;; - Don't try this in production, unless you really really really
200 | ;; know what your are doing.
201 |
202 |
203 | ;; Lesson:
204 | ;;
205 | ;; - Clojure programmers use `def` _only_ to attach values to globally
206 | ;; referenced names, for re-use. For example:
207 | ;; - The value of `pi` would be good global.
208 | ;; - The value of a function is often a good global.
209 | ;; (Recall: defn just wraps over def).
210 | ;;
211 | ;; - We rely on lexical scope to bind values as close as possible
212 | ;; to the place in code where the value is used. This makes code
213 | ;; much easier to reason about.
214 | ;;
215 | ;; - "Lexical scope" is super-important. Understand it and use it well,
216 | ;; for great good.
217 |
218 |
219 |
220 | ;; "Pure Functions"
221 |
222 |
223 | ;; This function is "pure"
224 | ;; - It is a mapping of input data -> output data and nothing more.
225 | (defn add-one
226 | [x]
227 | (+ x 1))
228 |
229 |
230 | ;; This function is "impure"
231 | ;; - Although it adds one to the input, it also changes the world on
232 | ;; the side, by sending out a value to some other place
233 | ;; - printing is a "side effect" who's outcome we cannot always predict
234 | (defn add-one!
235 | [x]
236 | (println x)
237 | (+ x 1))
238 | ;; - other examples of side-effects include:
239 | ;; - writing to a db (what if the db gets slow or unavailable?)
240 | ;; - or logging to console (what if the log file gets corrupted?)
241 |
242 |
243 | (add-one 1) ; adds one, but never changes the outside world
244 |
245 | (add-one! 1) ; adds one, and also changes the outside world
246 |
247 |
248 | ;; Pure functions are drop-in replacements for each other.
249 |
250 | (= 2
251 | ((fn [x] (+ x 1)) 1)
252 | (add-one 1)
253 | (inc 1))
254 |
255 | ;; Impure functions cannot be used as drop-in replacements for pure
256 | ;; functions, or for other impure functions for that matter.
257 |
258 |
259 | ;; RECAP:
260 | ;;
261 | ;; - Clojure values are immutable by default, and we prefer it that way
262 | ;;
263 | ;; - `def` is best used only to define names for truly global values.
264 | ;; Use `let` to bind local values, to get all the benefits of strict
265 | ;; lexical scope.
266 | ;;
267 | ;; - `defn` is just a wrapper over `def`, designed specifically to
268 | ;; define functions.
269 | ;;
270 | ;; - Write pure functions as far as possible.
271 |
272 | ;; 4clojure Drills: Problems you could try now.
273 | ;;
274 | ;; - #protip: Write the solutions as proper named functions in your code base,
275 | ;; without code-golfing or hacks. Then translate to anonymous function form
276 | ;; that 4clojure requires.
277 | ;;
278 | (comment
279 | (map (fn [problem-no] (str "https://4clojure.oxal.org/#/problem/"
280 | problem-no))
281 | [51, 77, 60, 102, 86, 115]))
282 |
--------------------------------------------------------------------------------
/tutorials/clojure-by-example/src/examples/fun/inspect_nasa_planets.clj:
--------------------------------------------------------------------------------
1 | (ns examples.fun.inspect-nasa-planets
2 | (:require [net.cgrand.enlive-html :as html]
3 | [clojure.string :as cs]
4 | [clojure.inspector :as inspect]))
5 |
6 | ;; Warning:
7 | ;; Code here may not be "professional" grade.
8 | ;;
9 | ;; This is just some fun messing around with some planetary data
10 | ;; published by NASA.
11 | ;;
12 | ;; Important:
13 | ;; Be kind to their servers, if you start tinkering with this code.
14 | ;;
15 | ;; First download a copy of the HTML pages to local disk,
16 | ;; and replace the URL with the absolute path to the file on disk.
17 | ;; Everything else should work the same.
18 |
19 |
20 | (def planets-to-earth-ratios-table
21 | {:table-name :planet-to-earth-ratios
22 | :table-data-file "https://nssdc.gsfc.nasa.gov/planetary/factsheet/"
23 | :num-cols 10
24 | :num-rows 20
25 | :rows-label-path [:table :tr [:td html/first-child] :a]
26 | :cols-label-path [:table [:tr html/first-child] :td :a]
27 | :stats-path [:table :tr (html/attr= :align "center")]})
28 |
29 |
30 | (def small-worlds-table
31 | {:table-name :small-worlds
32 | :table-data-file "https://nssdc.gsfc.nasa.gov/planetary/factsheet/galileanfact_table.html"
33 | ;; Of 12 cols, 11 have data, one is empty and must be removed
34 | ;; prior to processing.
35 | :num-cols 11
36 | :num-rows 16
37 | :rows-label-path [:table :tr [:td html/first-child] :b]
38 | :cols-label-path [:table [:tr html/first-child] :td :b]
39 | :stats-path [:table :tr (html/attr= :align "center")]})
40 |
41 |
42 | (defn file->html-resource
43 | "Given a path to a file, produce an Enlive 'html resource'."
44 | [file-or-url]
45 | (html/html-resource
46 | (java.io.StringReader.
47 | (slurp file-or-url))))
48 |
49 |
50 | (comment
51 | (let [checker (fn [table xy-key]
52 | (map :content
53 | (html/select
54 | (file->html-resource (:table-data-file table))
55 | (xy-key table))))
56 | check-pte (partial checker planets-to-earth-ratios-table)
57 | check-sw (partial checker small-worlds-table)
58 | check-all (juxt check-pte check-sw)]
59 | [(check-all :rows-label-path)
60 | (check-all :cols-label-path)]))
61 |
62 |
63 | (defn massage-table-info
64 | [{:keys [table-data-file num-cols num-rows] :as table-info}]
65 | (assoc table-info
66 | :num-stats (* num-cols num-rows)
67 | ;; Maybe not such a good idea to inject html-resource.
68 | ;; It could get really big. But then again, how to design the
69 | ;; api so that we can avoid parsing the DOM repeatedly?
70 | :html-resource (file->html-resource table-data-file)))
71 |
72 |
73 | (comment
74 | (massage-table-info planets-to-earth-ratios-table))
75 |
76 |
77 | (defn extract-raw-data
78 | [{:keys [html-resource stats-path
79 | rows-label-path cols-label-path]
80 | :as table-info}]
81 | (let [extract (partial html/select html-resource)]
82 | (dissoc (assoc table-info
83 | :col-labels (extract cols-label-path)
84 | :row-labels (extract rows-label-path)
85 | :stats-by-rows (extract stats-path))
86 | :html-resource)))
87 |
88 |
89 | (comment
90 | (-> planets-to-earth-ratios-table
91 | massage-table-info
92 | extract-raw-data))
93 |
94 |
95 | (def cleanup-table-data nil)
96 |
97 | (defmulti cleanup-table-data :table-name)
98 |
99 |
100 | (defmethod cleanup-table-data :planet-to-earth-ratios
101 | [{:keys [col-labels row-labels stats-by-rows
102 | num-cols num-stats]
103 | :as raw-table-info}]
104 | (let [keywordize (comp keyword
105 | #(cs/replace % #"\s+" "-")
106 | cs/lower-case)
107 | cleanup-labels #(->> %
108 | (map :content)
109 | flatten
110 | (map keywordize))]
111 | ;; replace labels and stats with cleaned up versions
112 | (assoc raw-table-info
113 | :row-labels (cleanup-labels row-labels)
114 | :col-labels (cleanup-labels col-labels)
115 | :stats-by-rows ((comp #(map flatten %)
116 | #(partition num-cols %)
117 | #(map :content %)
118 | #(take num-stats %)
119 | #(drop num-cols %))
120 | stats-by-rows))))
121 |
122 |
123 | (defmethod cleanup-table-data :small-worlds
124 | [{:keys [col-labels row-labels stats-by-rows
125 | num-cols num-stats]
126 | :as raw-table-data}]
127 | (let [keywordize (comp keyword
128 | #(cs/replace % #"\s+" "-")
129 | cs/lower-case)
130 | cleanup-cols #(->> %
131 | (map :content)
132 | flatten
133 | ((partial map
134 | (fn [s] (cs/replace s #"�" ""))))
135 | rest ; get rid of empty column's label
136 | (map keywordize))
137 | massage-row-label #(cond (#{:a} (:tag %))
138 | (:content %)
139 | (#{:sup} (:tag %))
140 | (apply str "^" (:content %))
141 | :else %)
142 | cleanup-rows (comp rest butlast ; get rid of empty row labels
143 | (partial
144 | map (comp keywordize
145 | #(cs/replace % #"_|\(|\)" "")
146 | #(apply str %)
147 | flatten
148 | (partial map massage-row-label)
149 | :content)))
150 | cleanup-stats (comp (partial partition num-cols)
151 | (partial filter #(not= "�" %))
152 | flatten
153 | #(map :content %)
154 | #(take num-stats %)
155 | #(drop (inc num-cols) %))]
156 | (assoc raw-table-data
157 | :col-labels (cleanup-cols col-labels)
158 | :row-labels (cleanup-rows row-labels)
159 | :stats-by-rows (cleanup-stats stats-by-rows))))
160 |
161 |
162 | (comment
163 | (-> planets-to-earth-ratios-table
164 | massage-table-info
165 | extract-raw-data
166 | cleanup-table-data)
167 |
168 | (-> small-worlds-table
169 | massage-table-info
170 | extract-raw-data
171 | cleanup-table-data))
172 |
173 |
174 | (defn transpose-matrix
175 | "The matrix must be a vector of vectors, where all nested vectors
176 | have the same number of items. "
177 | [matrix]
178 | (apply map vector matrix))
179 |
180 |
181 | (defn planet-properties
182 | [{:keys [col-labels row-labels stats-by-rows] :as table-data}]
183 | (let [stats-by-cols (transpose-matrix stats-by-rows)
184 | denormalise-row (fn [m k v]
185 | (assoc m k (zipmap row-labels v)))]
186 | (reduce-kv denormalise-row
187 | {}
188 | (zipmap col-labels stats-by-cols))))
189 |
190 |
191 | (defn planets-rel-earth
192 | []
193 | (-> planets-to-earth-ratios-table
194 | massage-table-info
195 | extract-raw-data
196 | cleanup-table-data
197 | planet-properties))
198 |
199 |
200 | (defn small-worlds
201 | []
202 | (-> small-worlds-table
203 | massage-table-info
204 | extract-raw-data
205 | cleanup-table-data
206 | planet-properties))
207 |
208 |
209 | (comment
210 | ;; Some repl-inspection
211 |
212 | ;; Try stuff
213 | (:jupiter (planets-rel-earth))
214 |
215 | (:callisto (small-worlds))
216 |
217 | ;; repl-print out the table like it appears in the HTML page
218 | (let [{:keys [col-labels row-labels stats-by-rows]}
219 | (-> planets-to-earth-ratios-table
220 | massage-table-info
221 | extract-raw-data
222 | cleanup-table-data)
223 | col-labels+ (into [:prop] col-labels)
224 | table (map (partial zipmap col-labels+)
225 | (map (fn [x xs] (into [x] xs))
226 | row-labels stats-by-rows))]
227 | (clojure.pprint/print-table col-labels+ table))
228 |
229 | ;; repl-print the inverted table (relative to input table)
230 | (let [table-data (planets-rel-earth)
231 | massage-for-pprint (fn [xs k v] (conj xs (assoc v :planet k)))
232 | table-data (reduce-kv massage-for-pprint [] table-data)]
233 | (clojure.pprint/print-table
234 | [:planet :mass :number-of-moons :distance-from-sun]
235 | table-data))
236 |
237 | ;; walk the tree, in a swing UI
238 | (inspect/inspect-tree (small-worlds)))
239 |
--------------------------------------------------------------------------------
/tutorials/clojure-by-example/src/examples/ex06_full_functional_firepower.clj:
--------------------------------------------------------------------------------
1 | (ns examples.ex06-full-functional-firepower
2 | (:require [clojure.data.json :as json]
3 | [clojure.java.io :as io]))
4 |
5 | ;; Ex06: Lesson Goals
6 | ;; - This is more of a code-reading section, designed to:
7 | ;;
8 | ;; - Show how to "keep state at the boundary"; e.g.:
9 | ;; - ingest sophisticated planets from a JSON file
10 | ;; ----------------Input boundary----------------
11 | ;; - punch it into a purely functional data processing pipeline
12 | ;; - do awesome things with just
13 | ;; - `map`, `filter`, `reduce`,
14 | ;; - simple helper functions (with/without control flow), and
15 | ;; - models of the world as pure data structures
16 | ;; ----------------Output boundary---------------
17 | ;; - spit out various kinds of outputs into output files
18 | ;;
19 | ;;
20 | ;; - Show where mutability is useful and desirable; e.g. I/O
21 | ;; (but where it isn't we try hard to avoid it)
22 | ;;
23 | ;; - Also give a feel for how we can use all the lessons learned
24 | ;; so far, to design flexible function APIs for good "composability".
25 |
26 |
27 |
28 |
29 | ;; Previously, in Clojure By Example...
30 | ;;
31 | ;; We lamented our immutable fate.
32 | ;;
33 | ;; WHY IS Clojure DOING THIS TO US???!!!
34 | ;;
35 | ;; And how are we to get anything done if we can't change things???
36 | ;;
37 | ;; HOW???
38 |
39 |
40 |
41 | ;; First, picture what a pure function does:
42 | ;;
43 | ;; [ Input Data ]
44 | ;; |
45 | ;; v
46 | ;; [ Function ] --->x NO side-effects allowed!
47 | ;; |
48 | ;; v
49 | ;; [ Output Data ]
50 | ;;
51 | ;; i.e. a pure function is a data -to-> data transformation.
52 |
53 |
54 |
55 | ;; Now, picture what _we_ want to do:
56 | ;;
57 | ;; [ Outside World ]
58 | ;; |
59 | ;; v
60 | ;; --------------------------------------------------
61 | ;; [ I/O Boundary ] ; Ingest the state of the World.
62 | ;; --------------------------------------------------
63 | ;; |
64 | ;; v
65 | ;; [ Input Data ] ; Values that we can't ever mutate.
66 | ;; |
67 | ;; v
68 | ;; [ Our Program ] ; A chain / pipeline of pure functions?
69 | ;; |
70 | ;; v
71 | ;; [ Output Data ] ; Values that we can't ever mutate.
72 | ;; |
73 | ;; v
74 | ;; --------------------------------------------------
75 | ;; [ I/O Boundary ] ; Update the state of the World.
76 | ;; --------------------------------------------------
77 | ;; |
78 | ;; v
79 | ;; [ Outside World ] ; New and Improved!
80 | ;;
81 | ;;
82 | ;; i.e., barring I/O Boundaries, where we read/write state,
83 | ;; could our whole program be a pure data-to-> data transformation?
84 |
85 |
86 | ;; Let's do this...
87 |
88 |
89 | ;; Outside World
90 | ;;
91 | ;; - A bunch of planetary sensors have written some JSON-formatted data
92 | ;; into some files on disk.
93 | ;;
94 | ;; - Our Planetary Data Scientists have told us the format for each
95 | ;; JSON file.
96 | ;;
97 | ;; - They want us to help them consolidate that data into a single file.
98 | ;;
99 | ;; - Maybe they will run batch jobs later? Who knows...
100 | ;;
101 | ;; - For now, we only need to prove to them that we can read their data,
102 | ;; and write to the file they want.
103 |
104 |
105 | ;; They told us sensors would dump files here...
106 | ;;
107 | (def sensor-data-dir
108 | "resources/sensor_data/")
109 |
110 |
111 | ;; They gave us:
112 | ;; - The file names for each sensor, and
113 | ;; - Told us the schema for the JSON in each file
114 | ;;
115 | ;; We decided to:
116 | ;; - Make a look-up table of files (as a hash-map), and
117 | ;; - Document the schema as in-line comments, for this dirty prototype.
118 | ;;
119 | (def sensor-data-files
120 | ;; {"Planet Name":{"radius":}, ...}
121 | {:planets "planet_detector.json"
122 |
123 | ;; {"Planet Name":, ...}
124 | :moons "moon_detector.json"
125 |
126 | ;; {"Planet Name":, ...}
127 | :atmosphere "atmospheric_detector.json"})
128 |
129 |
130 | ;; They told us:
131 | ;; - The file name to put the fully denormalized planetary data.
132 | ;;
133 | (def consolidated-data-file
134 | "consolidated_data.json")
135 | ;;
136 | ;; And, they said the JSON inside should follow this schema:
137 | ;;
138 | ;; [{"pname":"Planet Name",
139 | ;; "moons":,
140 | ;; "atmosphere":},
141 | ;;
142 | ;; {"pname" ...},
143 | ;;
144 | ;; {"pname" ...}]
145 |
146 |
147 | ;; ---------------------- Input Boundary begins ------------------------
148 |
149 | (defn ingest-json-file!
150 | [dir-path file-name]
151 | (let [file-path (str dir-path file-name)]
152 | (with-open [reader (io/reader file-path)]
153 | (json/read reader
154 | :key-fn keyword))))
155 |
156 |
157 | (defn gather-all-sensor-data!
158 | "Use our global collection of sensor keys to look up all the
159 | sensor data files, and ingest them at one go. Return a hash-map
160 | containing each sensor's data mapped to the corresponding sensor key."
161 | [data-dir sensor-files-map]
162 | (let [ingest-sensor-data
163 | (fn [out-map [sensor-key sensor-file]]
164 | (assoc out-map
165 | sensor-key (ingest-json-file! data-dir
166 | sensor-file)))]
167 | (reduce ingest-sensor-data
168 | {} ; out-map starts empty
169 | sensor-files-map)))
170 |
171 | #_(gather-all-sensor-data! sensor-data-dir
172 | sensor-data-files) ; try it
173 |
174 | ;; --------------------- Purely Functional Program begins --------------
175 |
176 |
177 | (defn add-sensor-data
178 | "Given a sensor key, a planetary hash-map, and a tuple having
179 | sensor data for a planet, inject the sensor data under the
180 | planet name found in the planetary hash-map."
181 | [sensor-key planets [pname sensor-pdata]]
182 | (assoc-in planets ; given these planets as a hash-map
183 | [pname sensor-key] ; follow this nested path
184 | sensor-pdata)) ; and assoc this value under that path
185 | ;; Note:
186 | ;; Just like `assoc` (into map) is the partner of `get` (from map),
187 | ;; `assoc-in` (nested map) is the partner of `get-in` (from nested map).
188 |
189 |
190 | (defn add-moon-data
191 | "Inject moons sensor data, into planets sensor data."
192 | [moons planets]
193 | (reduce (partial add-sensor-data :moons)
194 | planets
195 | moons))
196 |
197 |
198 | (defn add-atmosphere-data
199 | "Inject atmosphere sensor data, into planets sensor data."
200 | [atmosphere planets]
201 | (reduce (partial add-sensor-data :atmosphere)
202 | planets
203 | atmosphere))
204 |
205 |
206 | (defn denormalise-planetary-data*
207 | "Given a hash-map of planetary data (keyed by planet names),
208 | return just the planetary data, with the planet's names added in.
209 |
210 | Also ensure all keys are keywordized, for convenient look-ups."
211 | [planets]
212 | (map (fn [[pname pdata]]
213 | (assoc pdata
214 | :name (name pname)))
215 | planets))
216 |
217 |
218 | (defn denormalise-planetary-data
219 | "Given all sensor data, produce a collection of denormalized
220 | planetary data."
221 | [{:keys [planets atmosphere moons]
222 | :as all-sensor-data}]
223 | ((comp denormalise-planetary-data*
224 | (partial add-atmosphere-data atmosphere)
225 | (partial add-moon-data moons))
226 | planets))
227 |
228 |
229 | ;; ---------------------- Output Boundary begins -----------------------
230 |
231 |
232 | ;; First try this, to check packaged data...
233 | #_(denormalise-planetary-data
234 | (gather-all-sensor-data! sensor-data-dir
235 | sensor-data-files))
236 |
237 | ;; Does the result look familiar?
238 |
239 |
240 | (defn write-out-json-file!
241 | [dir-path file-name data]
242 | (let [file-path (str dir-path file-name)]
243 | (with-open [writer (io/writer file-path)]
244 | (json/write data writer))))
245 |
246 |
247 | (defn ingest-export-sensor-data!
248 | [data-dir source-data-files dest-data-file]
249 | (write-out-json-file!
250 | data-dir
251 | dest-data-file
252 | (denormalise-planetary-data
253 | (gather-all-sensor-data! data-dir source-data-files))))
254 |
255 |
256 | ;; Try it!
257 | #_(ingest-export-sensor-data!
258 | sensor-data-dir
259 | sensor-data-files
260 | consolidated-data-file)
261 |
262 | ;; --------------------- Output Boundary ends ------------------------
263 |
264 | ;; Done!
265 |
266 | ;; Or are we???
267 |
268 | ;; Because now...
269 |
270 | ;; The Planetary Data Scientists reveal their nefarious intentions:
271 |
272 | ;; (colonize-habitable-planets! ; deviously implemented by them, elsewhere
273 | ;; (denormalise-planetary-data
274 | ;; (gather-all-sensor-data! sensor-data-dir
275 | ;; sensor-data-files)))
276 |
277 |
278 | ;; RECAP:
279 | ;; - If we carefully keep side-effecting functions at our program
280 | ;; "boundary", we can design purely functional "core" logic.
281 | ;; This makes it much easier to reason about most of our program,
282 | ;; and to test it.
283 | ;;
284 | ;; - We could have written much more concise and well-abstracted
285 | ;; code, by using more Clojure features and utilities. However
286 | ;; this is not bad at all, and the point was to show we could
287 | ;; get this far quite easily, just with a handful of moving parts.
288 | ;;
289 | ;; - The next section will show you how to turn this file into
290 | ;; a complete project, that you can build and run as a
291 | ;; standalone executable.
292 |
--------------------------------------------------------------------------------
/header.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
101 |
366 |
367 |
368 | Project Name
369 |
370 |
371 | YOUR_SHORT_DESCRIPTION
372 |
373 |
374 |
375 |
390 |
391 |
392 |
393 |
394 |
--------------------------------------------------------------------------------
/tutorials/clojure-by-example/src/examples/ex04_api_design.clj:
--------------------------------------------------------------------------------
1 | (ns examples.ex04-api-design
2 | (:require [clojure-by-example.data.planets :as p]))
3 |
4 | ;; EX04: Lesson Goals:
5 | ;; - We use these conveniences for good effect in API design.
6 | ;; - See how to allow the same function to support different arities,
7 | ;; as well as a variable number of arguments
8 | ;; - See how to "de-structure" data (it's a powerful, flexible lookup mechanism)
9 | ;; - Leverage de-structuring to design a self-documenting function API
10 |
11 |
12 | ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
13 | ;;
14 | ;; Multiple arities
15 | ;;
16 | ;; - When we know for sure that a function must handle more than
17 | ;; one "arity". An "arity" is the number of arguments
18 | ;;
19 | ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
20 |
21 |
22 | (defn add-upto-three-nums
23 | ([] 0) ; identity of addition
24 | ([x] x)
25 | ([x y] (+ x y))
26 | ([x y z] (+ x y z)))
27 |
28 | (add-upto-three-nums)
29 | (add-upto-three-nums 1)
30 | (add-upto-three-nums 1 2)
31 | (add-upto-three-nums 1 2 3)
32 | #_(add-upto-three-nums 1 2 3 4) ; will fail
33 |
34 |
35 | ;; Variable arity
36 | ;; - When we don't know in advance how many arguments we
37 | ;; will have to handle, but we want to handle them all.
38 |
39 | (defn add-any-numbers
40 | [& nums]
41 | (reduce + 0 nums))
42 |
43 | (add-any-numbers)
44 | (add-any-numbers 1)
45 | (add-any-numbers 1 2)
46 | (add-any-numbers 1 2 3 4 5)
47 |
48 |
49 | ;; Multiple _and_ Variable arities, combined
50 | ;; - Guess what + actually is inside?
51 | ;;
52 | #_(clojure.repl/source +) ; evaluate, check the REPL
53 | ;;
54 | ;; See how + tries to implement each arity as a special case,
55 | ;; to compute results as optimally as possible? We can do
56 | ;; such things too, in functions we define.
57 |
58 | (+)
59 | (+ 1)
60 | (+ 1 2 3 4 5 6 7 8 9 0)
61 |
62 |
63 | ;; We can also use multiple arities to define sane fallbacks.
64 |
65 | ;; EXERCISE
66 | ;; - Recall `lower-bound`, and `upper-bound` from ex03
67 | ;; - Refactor these to support more than one arity.
68 |
69 | (def tolerances
70 | "Define low/high bounds of planetary characteristics we care about."
71 | {:co2 {:low 0.1, :high 5.0}
72 | :gravity {:low 0.1, :high 2.0}
73 | :surface-temp-deg-c {:low -125, :high 60}})
74 |
75 | (defn lower-bound
76 | [tolerance-key]
77 | (get-in tolerances [tolerance-key :low]))
78 |
79 | (defn upper-bound
80 | [tolerance-key]
81 | (get-in tolerances [tolerance-key :high]))
82 |
83 |
84 | ;; Fix `lower-bound-v2`, to make this expression evaluate
85 | ;; to true. Pay close attention to what should go where.
86 | (defn lower-bound-v2
87 | "Look up the lower bound for the given tolerance key, in the
88 | given map of `tolerances`. Use a globally-defined `tolerances`
89 | map as a sane default if only tolerance-key is passed in."
90 | ([tolerance-key]
91 | (get-in tolerances
92 | [tolerance-key :low]))
93 | ([FIX1 FIX2]
94 | 'FIX))
95 |
96 | #_(= (lower-bound :co2)
97 | (lower-bound-v2 :co2)
98 | (lower-bound-v2 :co2 tolerances)
99 | (lower-bound-v2 :co2 {:co2 {:low 0.1}}))
100 |
101 |
102 | (comment
103 | ;; BONUS EXERCISE
104 | ;; Do the same for `upper-bound-v2`
105 | #_(defn upper-bound-v2
106 | 'FIX
107 | 'FIX)
108 |
109 | #_(= (upper-bound :co2)
110 | (upper-bound-v2 :co2)
111 | (upper-bound-v2 :co2 tolerances)
112 | (upper-bound-v2 :co2 {:co2 {:low 0.1}}))
113 | )
114 |
115 |
116 | ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
117 | ;;
118 | ;; A tiny bit of "De-structuring"
119 | ;; - For convenient access to items in collections.
120 | ;;
121 | ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
122 |
123 | (comment
124 | ;; If we _shape_ our domain information as a data "structure",
125 | ;; can we use our knowledge of the shape to pull it apart;
126 | ;; i.e. "destructure" it?
127 |
128 | ;; Yes.
129 |
130 | ;; We use destructuring:
131 | ;; - In `let` bindings, to cleanly reach into data
132 | ;; - In function arguments, to make the API clean and expressive
133 | ;;
134 | ;; Here are a couple of commonly-used ways to do it.
135 | )
136 |
137 | ;; "Positional" De-structuring
138 | ;;
139 | ;; - Pull apart sequential, ordered data structures like
140 | ;; lists, vectors, and any other sequence with linear access
141 | ;;
142 | ;; - Follow the structure of the collection, and mechanically
143 | ;; bind values to symbols by position.
144 |
145 |
146 | ;; Evaluate and see what happens. Then form a theory of what might be going on.
147 | (def planet-names
148 | (map :pname p/target-planets))
149 |
150 |
151 | (let [[pname1 pname2] planet-names]
152 | (str pname1 " is the 1st planet, and "
153 | pname2 " is the 2nd planet."))
154 |
155 |
156 | (let [[:as pnames] planet-names]
157 | pnames)
158 |
159 |
160 | (let [[m v e :as pnames] (map :pname p/target-planets)]
161 | {:useless-trivia (str e " is the third rock from the Sun.")
162 | :planets-names pnames})
163 |
164 |
165 | ;; "Associative" De-structuring
166 | ;;
167 | ;; - Syntax to reach into associative data structures
168 | ;; (having key-value semantics), in arbitrary ways.
169 | ;;
170 | ;; - Note: Clojure "Records" and vectors are associative too
171 | ;;
172 | ;; - Follow the structure of the collection, and mechanically
173 | ;; bind values to symbols by key name.
174 |
175 | ;; Evaluate one by one and see what happens.
176 | ;; Then form a theory of what might be going on.
177 |
178 |
179 | (let [[mercury] p/target-planets]
180 | (str (:pname mercury) " has mass " (:mass mercury)))
181 |
182 |
183 | (let [[{:keys [pname mass]}] p/target-planets]
184 | (str pname " has mass " mass))
185 |
186 |
187 | (let [[{:keys [pname mass] :as mercury}] p/target-planets]
188 | (assoc mercury
189 | :useless-trivia (str pname " has mass " mass)))
190 |
191 |
192 |
193 | ;; And, putting it all together, a function with a
194 | ;; more self-documented API:
195 |
196 | (defn add-useless-trivia
197 | "Be Captain Obvious. Given a planet, add some self-evident trivia to it."
198 | [{:keys [pname mass] :as planet}]
199 | (assoc planet
200 | :useless-trivia (str pname " has mass " mass)))
201 |
202 |
203 | (map add-useless-trivia
204 | p/target-planets)
205 |
206 | #_(clojure.repl/doc add-useless-trivia)
207 |
208 |
209 | ;; EXERCISE:
210 | ;; Review the de-structured argument list in `add-useless-trivia`;
211 | ;; then try to recall and reinforce a key concept.
212 | ;; Hints:
213 | ;; - Relate it to our preferred way to model the world.
214 | ;; - What is the "world" here?
215 | ;; - What are we using to model/describe what property of what?
216 | ;; (Yes, that's three 'what's :-)
217 |
218 |
219 | ;; EXERCISE:
220 | ;;
221 | ;; - Use de-structuring to refactor the following functions
222 | ;; that we have copied over from ex03.
223 | ;;
224 | ;; - Develop a preliminary opinion about where and when
225 | ;; it might makes sense to de-structure, and where and when
226 | ;; it might not.
227 |
228 |
229 | (defn atmosphere-present?
230 | [planet]
231 | (not (empty? (:atmosphere planet))))
232 |
233 |
234 | (defn atmosphere-present?-refactored
235 | [FIXME]
236 | FIXME)
237 |
238 | #_(= (map :pname
239 | (filter atmosphere-present? p/target-planets))
240 | (map :pname
241 | (filter atmosphere-present?-refactored
242 | p/target-planets)))
243 |
244 | (defn co2-tolerable?
245 | [planet]
246 | (let [co2 (get-in planet
247 | [:atmosphere :carbon-dioxide])]
248 | (when co2
249 | (<= (lower-bound :co2)
250 | co2
251 | (upper-bound :co2)))))
252 |
253 |
254 | (defn co2-tolerable?-refactored
255 | [FIXME]
256 | FIXME)
257 |
258 | #_(= (map :pname
259 | (filter co2-tolerable? p/target-planets))
260 | (map :pname
261 | (filter co2-tolerable?-refactored
262 | p/target-planets)))
263 |
264 |
265 | ;; EXERCISE:
266 | ;; - Fix the body of the refactored function
267 | ;; - Carefully review the function APIs, and develop a preliminary
268 | ;; opinion whether the refactored version is better than the original.
269 |
270 |
271 | (defn surface-temp-tolerable?
272 | [planet]
273 | (let [temp (:surface-temp-deg-c planet)
274 | low (:low temp)
275 | high (:high temp)]
276 | (when (and low high)
277 | (<= (lower-bound :surface-temp-deg-c)
278 | low
279 | high
280 | (upper-bound :surface-temp-deg-c)))))
281 |
282 |
283 | (defn surface-temp-tolerable?-refactored
284 | [{:keys [FIXME] :as planet}]
285 | FIXME)
286 |
287 |
288 | (defn surface-temp-tolerable?-refactored-v2
289 | [{{:keys [low high]} :surface-temp-deg-c
290 | :as planet}]
291 | 'FIXME)
292 |
293 |
294 | #_(= (map :pname
295 | (filter surface-temp-tolerable?
296 | p/target-planets))
297 | (map :pname
298 | (filter surface-temp-tolerable?-refactored
299 | p/target-planets))
300 | (map :pname
301 | (filter surface-temp-tolerable?-refactored-v2
302 | p/target-planets)))
303 |
304 |
305 | ;; RECAP:
306 | ;;
307 | ;; - We model the world by composing data structures and then use
308 | ;; "de-structuring" to conveniently reach into those structures.
309 | ;; - We can design function apis to accept more than one arity,
310 | ;; and then define custom logic for each arity.
311 | ;; - When, where, and how much to de-structure is a matter of
312 | ;; taste; a design choice. There is no One True Way.
313 | ;; - There are _many_ many ways of de-structuring.
314 | ;; Here's a really nice post detailing it:
315 | ;; cf. http://blog.jayfields.com/2010/07/clojure-destructuring.html
316 |
317 | ;; 4clojure Drills: Problems you could try now.
318 | ;;
319 | ;; - #protip: Write the solutions as proper named functions in your code base,
320 | ;; without code-golfing or hacks. Then translate to anonymous function form
321 | ;; that 4clojure requires.
322 | ;;
323 | (comment
324 | (map (fn [problem-no] (str "https://4clojure.oxal.org/#/problem/"
325 | problem-no))
326 | [35, 36, 68, 145, 52,
327 | 156, 22, 23, 32, 30,
328 | 34, 28, 33, 40, 83,
329 | 61, 99, 120, 56, 55,
330 | 43, 67, 74, 80, 69, 75]))
331 |
--------------------------------------------------------------------------------
/tutorials/clojure-by-example/README.md:
--------------------------------------------------------------------------------
1 | - [Introduction](#introduction)
2 | - [Intended usage](#intended-usage)
3 | - [Contributions](#contributions)
4 | - [Workshop Goals](#workshop-goals)
5 | - [Workshop Anti-Goals](#workshop-anti-goals)
6 | - [Suggested learning mindset](#suggested-learning-mindset)
7 | - [Setup Instructions](#setup-instructions)
8 | - [Course Design Philosophy](#course-design-philosophy)
9 | - [Credits](#credits)
10 | - [Copyright and License](#copyright-and-license)
11 |
12 |
13 | # Introduction
14 |
15 | This workshop aims to get your brain and fingers accustomed to just enough of
16 | the [Clojure](https://clojure.org) programming language to start doing useful things with it.
17 |
18 | In other words, "What could one do with just a _little_ bit of Clojure?".
19 |
20 | ## What is Clojure?
21 |
22 | Clojure is an interactive functional programming language that can run on many platforms
23 | like the [JVM](https://clojure.org/about/jvm_hosted), [.NET CLR](https://clojure.org/about/clojureclr), [Javascript](https://clojurescript.org/) (browsers, nodeJS, React Native), as [native binaries](https://github.com/BrunoBonacci/graalvm-clojure) via Graalvm, and even as [shell scripts](https://babashka.org/)!
24 |
25 | It is [used by software teams worldwide](https://clojure.org/community/success_stories#) to deliver
26 | high-value software systems at giant companies like Apple, Walmart, to "decacorns"
27 | like GoJek, Nubank, to a wide array of startups, and one-person businesses like Partsbox.com.
28 |
29 | Its interactivity and dynamism foster a sense of playfulness that attracts all manner
30 | of [creative makers](http://radar.oreilly.com/2015/05/creative-computing-with-clojure.html)---hobbyist as well as serious artists and musicians.
31 |
32 | A small but vibrant [global community](https://clojure.org/community/user_groups) is [busy building amazing things](https://github.com/trending/clojure?since=monthly) with the language.
33 |
34 | ## Intended usage
35 | - Support a 1-day guided workshop for programmers new to Clojure (not absolute programming beginners).
36 | - Also function as at-home learning material for said programmers.
37 | - The `master` branch is heavily commented, for at-home use
38 | - A `solutions` branch will be available, as a companion to `master`.
39 | But don't peek at it in advance!
40 | - You may see a `workshop-code` branch. Ignore it. It is meant only for
41 | workshop use, and is subject to deletion/re-creation.
42 | - Incidentally, if you landed here while searching for Hirokuni Kim's
43 | "[Clojure By Example](https://kimh.github.io/clojure-by-example/)", well, follow the link!
44 |
45 | ## Contributions
46 | - If you find bugs or errors, please send a PR (but please
47 | don't change the course structure or pedagogy).
48 |
49 | ## Workshop Goals
50 | - Acquire a "feel" of Clojure, for further self-study/exploration.
51 | - Learn how Clojurists usually think with Clojure to solve problems.
52 | - See how it's not so hard to do surprisingly powerful things with a
53 | mere handful of "primitive" functions, data structures, and ideas.
54 | - Get you started with a good development setup and workflow that will
55 | serve you well if (when) you continue to program with Clojure, as a
56 | hobby, or at work!
57 |
58 | ## Workshop Anti-Goals
59 | - Try to explain Functional Programming theory or Clojure's innards.
60 | (Many free and paid tutorials and books do so very well.)
61 | - Try to fully cover Clojure primitives/features. (That's homework!)
62 | - Devolve into language wars, editor wars, syntax wars, type wars...
63 | (Life's too short, people.)
64 | - Focus too much on tooling or operational things. (At least not
65 | while there's fun to be had!)
66 |
67 |
68 | # Suggested learning mindset
69 | - Think of this as an exercise in "constrained creativity".
70 | - Ignore details, achieve much with as little know-how as possible.
71 | - Focus on what things do; not what they are, or why they are.
72 | - Inform your _intuition for doing things_, and then use that to
73 | dive deeper into all the juicy details at your own pace, later.
74 |
75 | Take what is useful, discard the rest.
76 |
77 |
78 | # Setup Instructions
79 |
80 | It's a liiitle bit of work. But not too bad.
81 |
82 | Just do the following one by one, and you should be fine.
83 |
84 | ## IntelliJ + Cursive IDE
85 |
86 | We support IntelliJ + Cursive IDE in the classroom for this workshop. We suggest you use this setup, unless of course, you have already configured your favourite editor for Clojure development. We've listed alternate starter kits below (VSCode, Vim, Emacs, Atom), *but* please avoid [bikeshedding](http://catb.org/jargon/html/B/bikeshedding.html) editors. Just complete the workshop first!
87 |
88 | - Download and Install [IntelliJ Community Edition](https://www.jetbrains.com/idea/download/)
89 | - Install and configure the Cursive plugin for IntelliJ by following the [official Cursive user guide](https://cursive-ide.com/userguide/).
90 |
91 | Once installed:
92 |
93 | - Launch IntelliJ and select "Import Project" from the opening splash screen.
94 | - OR use IntelliJ's file menu to open this project via File > New > Project From Existing Sources
95 | - Select this project's main directory; click OK
96 | - The "Import Project" dialog box should open
97 | - Select Leiningen under "Import project from external model"; click Next
98 | - Click Next again in the following screen that shows "Root Directory"; wait for it...
99 | - Again, click Next in the screen that says "Select Leiningen projects to import"
100 | - And again, click Next in the "Please select project SDK" screen (ensure you select JDK version 1.8 or higher)
101 | - Click "Finish", and wait for IntelliJ to set up the project
102 | - Under `Run...` click on `Run...` and then select `REPL for clojure-by-example` (or whatever your project name happens to be).
103 | - A right pane should open, with a REPL session.
104 | - Now, open the `ex00..` file under the `src` folder
105 | - Use the menu under Tools > REPL to (a) Switch to the file's "namespace", and then (b) load the file into the REPL
106 | - Scroll down a little, till you see `(+ 1 2)`.
107 | - Place your cursor after the closing parenthesis `)`, then right-click to open the context menu, and click on REPL > "Send '(+ 1 2)' to the REPL.
108 | - You should see '(+ 1 2)' appear in the REPL window, followed by `3`. This means you successfully evaluated an expression in the REPL.
109 | - Now you may start from the top of ex00 and work through the material in each "ex" file
110 | - Important: For every exercise file, remember to first switch to the file's namespace, and load the file in the REPL (use the menu under Tools > REPL)
111 |
112 | Also keep the Cursive user guide handy, in case you need editor help, as you solve the workshop material. In particular, the [Paredit guide](https://cursive-ide.com/userguide/paredit.html) may be useful, if you stumble when editing Clojure code.
113 |
114 | ## (Optional) Java and Leiningen
115 | Being a JVM hosted language, Clojure requires Java to run. For the workshop, we also use a Clojure build tool called Leiningen.
116 | If you're using IntelliJ + Cursive for the workshop, you won't need to install Java or Leiningen separately, since Intellij will come with a JDK and Cursive will download Leiningen when you import the project.
117 | So just follow the IntelliJ + Cursive setup guide and you'll be good to go for the workshop.
118 |
119 | If you're working on a production project however, it's useful to have both Java and Leiningen separately installed.
120 |
121 | ### Java
122 |
123 | - Run `java -version` in your terminal.
124 | - If Java is not installed, please [download and install Java from here](https://adoptopenjdk.net/). Any version should do.
125 | - Once you are done, `java -version` should show you a Java version.
126 |
127 | Notes:
128 | - We have not tested this project with Java 7.
129 |
130 |
131 | ### Leiningen
132 |
133 | Follow [Leiningen setup instructions here](https://leiningen.org/).
134 |
135 | ## Alternative Starter Kits:
136 |
137 | If you can't use IntelliJ for some reason, you may try one of these. Although we haven't tested with these setups, the workshop material should work fine.
138 | You'll also have to install Leiningen and Java separately.
139 |
140 | - [VSCode + Calva](https://calva.io/) has become a fantastic Clojure IDE!
141 | - A [snazzy setup with Atom](https://medium.com/@jacekschae/slick-clojure-editor-setup-with-atom-a3c1b528b722).
142 | - [Vim + vim-fireplace](https://thoughtbot.com/blog/writing-clojure-in-vim) and other goodies that make Clojure/Lisp hacking fun in Vim.
143 | - Brave Clojure walks you through [a basic Emacs setup for learning Clojure](https://www.braveclojure.com/basic-emacs/).
144 |
145 |
146 | ## Your favourite editor:
147 |
148 | You may find instructions for your favourite editor at one of these pages. But there are only so many choices. Ultimately, you must pick your poison and run with it:
149 |
150 | - ["Clojure Tools" at clojure.org](https://clojure.org/community/tools)
151 | - ["Essentials" at clojure-doc.org](http://clojure-doc.org/articles/content.html#essentials)
152 | - [Christopher Bui says...](https://web.archive.org/web/20181223213500/https://cb.codes/what-editor-ide-to-use-for-clojure/)
153 |
154 |
155 | # Course Design Philosophy
156 |
157 | Just some peoples' opinion. You need not be slave to it ;-)
158 |
159 | Almost anyone can hope to do more with more. Up to a point, that is.
160 |
161 | Far too often, we end up doing _less_ with more; bogged down by the
162 | complexity and blinding glitter of too much choice, and overabundance.
163 |
164 | Figuring out how to do more with less feeds our curiosity, and it often
165 | satisfies and empowers us deeply.
166 |
167 | So, may you stay small and achieve important things.
168 |
169 | Live long, and prosper.
170 | \\\\//_
171 |
172 |
173 | # Credits
174 | - [clj-pune](https://github.com/clj-pune) people, especially [kapilreddy](https://github.com/kapilreddy), and [jaju](https://github.com/jaju) for critique while making ["pratham"](https://github.com/clj-pune/pratham), the precursor to this project.
175 | - [adityaathalye](https://github.com/adityaathalye), [jysandy](https://github.com/jysandy), and [kapilreddy](https://github.com/kapilreddy) for course design, code reviews, critique, commits, and being the core teaching staff at the first edition of this workshop at IN/Clojure 2018.
176 | - All the workshop participants, and the many Clojurists who generously donated their time to make it successful.
177 | - [inclojure-org](https://github.com/inclojure-org) for being the umbrella under which this work happened.
178 |
179 | ## Copyright and License
180 |
181 | Copyright © 2017-2018 [IN/Clojure](http://inclojure.org/).
182 |
183 | Distributed under the [MIT license](https://github.com/inclojure-org/clojure-by-example/blob/master/LICENSE).
184 |
--------------------------------------------------------------------------------
/tutorials/clojure-by-example/src/examples/ex01_fundamentally_functional.clj:
--------------------------------------------------------------------------------
1 | (ns examples.ex01-fundamentally-functional)
2 |
3 | ;; EX01: LESSON GOAL:
4 | ;; - Realize that pure functions, and strict lexical scope
5 | ;; are the bedrock upon which Clojure programs are built
6 | ;; - Drill how to use functions, and how lexical scope works
7 | ;; - Get comfortable with how functions compose together
8 | ;; - At every step, further drill the interactive REPL workflow.
9 | ;; Figure out how to take advantage of the immediate feedback
10 | ;; that the live REPL gives you. Treat each exercise as a
11 | ;; tiny experimental setup. Run small experiments that will
12 | ;; help you discover answers...
13 | ;; -> Read the exercise
14 | ;; -> Make a testable guess (hypothesis)
15 | ;; -> Evaluate your solution (test your hypothesis)
16 | ;; -> Compare your guess with the solution
17 | ;; -> If it differs, update your guess (or fix the solution) and redo
18 | ;; That is, try to use the Scientific Method to solve exercises.
19 |
20 |
21 | ;; Basic Function Syntax
22 | ;;
23 | ;; - Named functions:
24 | ;;
25 | (defn function-name
26 | "Documentation string (optional)."
27 | [arg1 arg2 arg3 etc up to argN]
28 | 'function 'body
29 | 'goes 'here
30 | '...)
31 |
32 | ;; - Anonymous functions:
33 | ;;
34 | (fn [arg1 arg2 arg3 etc up to argN]
35 | 'function 'body
36 | 'goes 'here
37 | '...)
38 |
39 |
40 |
41 | ;; A dead-simple function:
42 |
43 | (defn same
44 | "Simply return the input unchanged."
45 | [x]
46 | x)
47 |
48 |
49 | (fn [x] x) ; just like `same`, but with no name
50 |
51 |
52 |
53 | ;; EXERCISE
54 | ;;
55 | ;; Evaluate and see:
56 |
57 | (same 42)
58 |
59 | (same [1 2 3 4 5])
60 |
61 | (same {:pname "Earth" :moons 1})
62 |
63 | ;; EXERCISE
64 | ;; How about the anonymous version of `same`?
65 | ;; - What's the evaluation model? Think before you tinker.
66 | ;; - Form your hypothesis -> Test it -> Learn from the feedback
67 |
68 | ((fn [x] x) 42)
69 |
70 | ((fn [x] x) [1 2 3 4 5])
71 |
72 | ((fn [x] x) {:pname "Earth" :moons 1})
73 |
74 |
75 | ;; EXERCISE
76 | ;; Fix the the following s-expr, so that it evaluates to true.
77 | ;; - First predict the solution in your head.
78 | ;; - Then replace 'FIX with your solution and evaluate to confirm.
79 | ;; - Think about the little experiment you just performed, and
80 | ;; form a theory about why the solution worked
81 | (= 'FIX
82 | (same same)
83 | ((fn [x] x) same))
84 |
85 |
86 | ;; `identity`
87 | ;; - provided by Clojure
88 | ;; - is exactly like our`same` function
89 | ;; - is extremely general (accepts any value)
90 | ;; - is surprisingly useful, as we will discover later
91 |
92 | ;; EXERCISE
93 | ;; Fix this to prove `identity`, `same`, and the anonymous
94 | ;; version of `same`, all do the exact same thing:
95 | ;; - Note: Functions are values and can therefore be compared.
96 | ;;
97 | (= identity
98 | ('FIX identity)
99 | ('FIX identity)
100 | ('FIX identity))
101 | ;;
102 | ;; Now, evaluate this in the REPL to _see_ the truth:
103 | ;;
104 | #_(clojure.repl/source identity)
105 | ;;
106 | (comment
107 | ;; This is another example of what "dynamic" means.
108 | ;; We can not only can we interact live with small bits of
109 | ;; our Clojure programs, we can also examine many aspects
110 | ;; of our programs at run time. The clojure.repl namespace
111 | ;; is one tool at our disposal. Try these in the REPL:
112 | #_(clojure.repl/dir clojure.repl)
113 | #_(clojure.repl/doc clojure.repl)
114 | )
115 |
116 |
117 | ;; "Higher order" functions (HoFs):
118 |
119 | ;; Functions that:
120 | ;; - *accept* functions as arguments
121 | ;; and/or
122 | ;; - *return* functions as results
123 | ;; are called "higher order" functions.
124 |
125 |
126 | ;; EXERCISE
127 | ;; Have we seen HoFs so far? If yes, list them out below.
128 |
129 |
130 | ;; EXERCISE
131 | ;; Write a zero-argument function that returns the `identity` function
132 |
133 | (defn gen-identity
134 | [] ; zero arguments
135 | 'FIX)
136 |
137 | ;; EXERCISE
138 | ;; Fix this function so that it returns a function that _behaves_
139 | ;; like the identity function (don't return `same`, or `identity`).
140 |
141 | (defn gen-identity-v2
142 | []
143 | 'FIX)
144 |
145 | ;; EXERCISE
146 | ;; Replace 'FIX1 with a call to the `gen-identity` function,
147 | ;; and 'FIX2 with a call to the `gen-identity-v2` function,
148 | ;; such that the following evaluates to true.
149 |
150 | (= identity
151 | 'FIX1
152 | 'FIX2)
153 |
154 |
155 | ;; Composing Logic with Higher-order Functions (HoFs):
156 | (comment
157 | ;; Clojure programmers often write simple functions that
158 | ;; each do one task well, and use higher order functions
159 | ;; to "compose" these in creative ways, to produce more
160 | ;; useful pieces of logic.
161 | ;;
162 | ;; We treat "simple" functions as building blocks, and
163 | ;; HoFs as versatile mini-blueprints that help us organize
164 | ;; and glue together the simple functions.
165 | )
166 |
167 | ;; EXERCISE
168 | ;; Reason about why this is working:
169 |
170 | (defn selfie
171 | "Given a function `f`, return the result of
172 | applying `f` to itself."
173 | [f]
174 | (f f))
175 |
176 | (= 42
177 | (identity 42)
178 | ((selfie identity) 42)
179 | ((selfie (selfie identity)) 42)
180 | ((selfie (selfie (selfie identity))) 42)) ; ad-infinitum
181 |
182 |
183 | ;; Let's play with a couple of nifty HoFs built into Clojure
184 | ;; - `comp`
185 | ;; - `complement`
186 |
187 |
188 | ;; EXERCISE
189 | ;; Use `(comp vec str inc)` to make the following true
190 | ;; - `comp` accepts any number of functions as arguments,
191 | ;; and returns a function that behaves as a pipeline
192 | ;; (or chain) of the given functions
193 |
194 | (= [\4 \2]
195 | (vec (str (inc 41)))
196 | ('FIX 'FIX))
197 |
198 | (comment
199 | ;; Reason about the order of evaluation and how inputs
200 | ;; and outputs should connect, for `comp` chains to
201 | ;; work correctly.
202 | ;;
203 | ;; To see if you reasoned correctly, try each of
204 | ;; seq, str, inc independently:
205 | (inc 41) ; increment a number
206 | (str 42) ; turn the input into a string
207 | (seq "42") ; turns a string into a character sequence
208 | )
209 |
210 |
211 | ;; EXERCISE
212 | ;; Use `(complement string?)` to make the following true
213 | ;; - `complement` accepts a "predicate" function, and returns a
214 | ;; function that does the opposite of the given "predicate"
215 | (= (not (string? "hi"))
216 | ('FIX 'FIX))
217 |
218 | (comment
219 | ;; "Predicate" is just a term we use to conveniently describe
220 | ;; any function that returns a truthy/falsey value, i.e.
221 | ;; any function that is used to test for some condition.
222 | ;; These so-called "predicates" are not inherently special.
223 | )
224 |
225 |
226 |
227 | ;; "Lexical Scope" in Clojure
228 | ;; - Lexical scope guarantees that the reference to a value will be
229 | ;; "enclosed" in the scope in which it is being used.
230 |
231 | (comment
232 | ;; Strict lexical scope greatly simplifies our life, because
233 | ;; it allows us to mechanically follow code, and determine
234 | ;; where a value originated.
235 | ;; - Start at the place of reference of the value.
236 | ;; - Then "walk" outwards, until you meet the very first let binding,
237 | ;; or arg-list, or def, where the value was bound.
238 | ;; - Now you know where the value came from.
239 | ;;
240 | ;; This also helps reduce our mental burden of inventing
241 | ;; new names to refer to things, because we can re-use
242 | ;; a name within a limited scope, and be certain that
243 | ;; it will not destroy anything with the same name outside
244 | ;; the given scope.
245 | )
246 |
247 | ;; EXERCISE:
248 | ;; - Develop an intuition for what "Lexical scope" might mean
249 | ;; by reasoning about the following exercises.
250 | ;;
251 | ;; - Mentally evaluate and predict the results; then check.
252 |
253 | (def x 42) ; Bind `x` to 42, globally ("top-level" binding)
254 |
255 | (identity x) ; obviously returns 42
256 |
257 | ((fn [x] x) x) ; also returns 42, but how?
258 |
259 | (let [x 10] ; We use `let` to bind things locally.
260 | x) ; This evaluates to the value of the "let-bound" `x`.
261 |
262 | (+ (let [x 10]
263 | x)
264 | x) ; So, this whole thing should evaluate to what?
265 |
266 |
267 | ;; EXERCISE
268 | ;; Read carefully, and compare these three function variants:
269 |
270 | (defn add-one-v1
271 | [x]
272 | (+ x 1)) ; which `x` will this `x` reference?
273 |
274 | (add-one-v1 1) ; should evaluate to what?
275 | (add-one-v1 x) ; should evaluate to what?
276 |
277 |
278 | (defn add-one-v2
279 | [z]
280 | (+ x 1)) ; which `x` will this `x` reference?
281 |
282 | (add-one-v2 1) ; should evaluate to what?
283 | (add-one-v2 x) ; should evaluate to what?
284 |
285 |
286 | (defn add-one-v3
287 | [x]
288 | (let [x 10]
289 | (+ x 1))) ; which `x` will this `x` reference?
290 |
291 | (add-one-v3 1) ; should evaluate to what?
292 | (add-one-v3 x) ; should evaluate to what?
293 |
294 |
295 | ;; EXERCISE
296 | ;; - Mentally evaluate the following, predict the results,
297 | ;; and try to infer the scoping rule.
298 | ;; - Then evaluate each expression to see if your
299 | ;; mental model agrees with the result you see.
300 | ;; - Start with any `x`, and mechanically work
301 | ;; your way around.
302 |
303 | ((fn [x] x) (let [x 10] x))
304 |
305 |
306 | ((fn [x] x) (let [x x] x))
307 |
308 |
309 | (let [x 10] ((fn [x] x) x))
310 |
311 |
312 | ((let [x 10] (fn [x] x)) x)
313 |
314 |
315 | ;; Function "Closure"
316 | ;; - This is a way for a function to capture and "close over"
317 | ;; any value available at the time the function is defined
318 |
319 | (def PI 3.141592653589793)
320 |
321 | (defn scale-by-PI
322 | [n]
323 | (* n PI)) ; PI is captured within the body of `scale-by-PI`
324 |
325 | (scale-by-PI 10)
326 |
327 |
328 | ;; A more general way to "scale by":
329 | ;; - Thanks to lexical scope + the function closure property
330 |
331 | (defn scale-by
332 | "Given a number `x`, return a function that accepts
333 | another number `y`, and scales `y` by `x`."
334 | [x]
335 | (fn [y] (* y x))) ; whatever is passed as `x` is captured
336 | ; within the body of the returned function
337 |
338 |
339 | ;; EXERCISE
340 | ;;
341 | #_(= (scale-by-PI 10)
342 | ('FIX 10)
343 | (* PI 10))
344 |
345 | (comment
346 | ;; BONUS EXERCISES
347 | ;; Define a few scaling functions, in terms of `scale-by`
348 | ;;
349 | (def scale-by-PI-v2
350 | 'FIX)
351 |
352 | (def quadruple
353 | "4x the given number."
354 | 'FIX)
355 |
356 | (def halve
357 | 'FIX))
358 |
359 |
360 | ;; Sequences (or Collections)
361 | ;;
362 | ;; - and operations on Sequences
363 | ;; - Clojure provides _many_ sequence functions.
364 | ;; Here are some important ones: `map`, `filter`, and `reduce`
365 | ;; - Observe that all these functions are HoFs!
366 |
367 | map
368 | ;; Basic Syntax:
369 | ;;
370 | ;; (map a-function a-collection)
371 | ;;
372 | ;; Where the function must accept exactly one argument, because
373 | ;; it must transform only one item of the input at a time.
374 |
375 | (map inc [1 2 3 4 5 6])
376 | ;; | | | | | | ; declare a mapping of each item of the input coll
377 | ;; inc inc inc ; via `inc`
378 | ;; | | | | | |
379 | ;; (2 3 4 5 6 7) ; to each item of the output coll
380 | ;;
381 | ;; Note: you may wonder why the result of map inc on [1 2 3 4], which is
382 | ;; square-bracketed results in an answer that's wrapped in parens (2 3 4 5).
383 | ;;
384 | ;; The short answer is: Ignore this pesky detail.
385 | ;; Think in terms of "sequence in, sequence out", instead of "this 'type' of
386 | ;; sequence in, and the same 'type' of sequence out".
387 | ;;
388 | ;; The more confusing answer is: 'map' returns a "lazy" sequence, which the REPL
389 | ;; _prints_ out visually, with round parens. 'filter' (below) does the same too.
390 | ;;
391 | ;; Usually we don't care if we have a vector or a list or a "lazy" sequence.
392 | ;; What we do care is what the sequence contains, and that the thing remains
393 | ;; sequential before/after. It only starts mattering when we definitely want
394 | ;; a particular sequence type for the very specific performance guarantees
395 | ;; that it provides.
396 | ;;
397 | ;; But really, you'll do better if you just ignore what this actually means
398 | ;; and/or the consequences of the distinction for now.
399 |
400 |
401 | filter
402 | ;; Basic Syntax:
403 | ;;
404 | ;; (filter a-predicate-fn a-collection)
405 | ;;
406 | ;; Where the function must accept exactly one argument and
407 | ;; return a truthy result (hence we term it a "predicate" function).
408 |
409 | (filter even? [1 2 3 4 5 6])
410 |
411 | (filter identity [1 nil 3 nil 5 nil]) ; nil is falsey, non-nils are truthy
412 |
413 |
414 | reduce
415 | ;; Basic Syntax:
416 | ;;
417 | ;; (reduce a-function accumulator a-collection)
418 | ;;
419 | ;; Where the function must accept two arguments:
420 | ;; - first one is the value of the accumulator it manages, and
421 | ;; - the second one is bound to each item of the collection
422 |
423 | (reduce + 0 [0 0 1 2])
424 |
425 | ;; Imagine each step of the above computation, like this:
426 |
427 | ;; =======================================
428 | ;; Accumulator | Input collection (of number of moons)
429 | ;; =======================================
430 | ;; 0 (start) | [0 0 1 2] ; just before first step
431 | ;; 0 | [0 1 2] ; at end of first step
432 | ;; 0 | [1 2]
433 | ;; 1 | [2]
434 | ;; 3 | [] ; reduce detects empty collection
435 | ;; ---------------------------------------
436 | ;; 3 (return value) ; reduce spits out the accumulator
437 |
438 |
439 |
440 | ;; Truthiness
441 | ;;
442 | ;; - Only `nil` and `false` are Falsey; everything else
443 | ;; is Truthy
444 | ;; - a "predicate" function can return Truthy/Falsey,
445 | ;; not just boolean true/false
446 | ;; - we can make good use of this behaviour, in Clojure
447 |
448 |
449 | (def a-bunch-of-values
450 | [nil, false, ; falsey
451 | 42, :a, "foo", true, ; truthy
452 | {:a 1, :b 2}, [1 2 3 4], ; truthy
453 | '(), {}, [], ""]) ; truthy
454 |
455 |
456 | ;; A quick proof:
457 | (map boolean ; coerces a given value to boolean true or false
458 | a-bunch-of-values)
459 |
460 | (filter boolean
461 | a-bunch-of-values)
462 |
463 |
464 | ;; Branching logic accepts Truthy/Falsey
465 |
466 | (if nil ; if condition is Truthy
467 | "hi!" ; then evaluate the first expression
468 | "boo!") ; else evaluate the second expression
469 |
470 |
471 | (when false ; only when the condition is truthy
472 | "boo!") ; evaluate the body. Otherwise, always return `nil`
473 |
474 |
475 |
476 | ;; RECAP
477 | ;; - Acquire a "scientific experimentation" mindset when
478 | ;; interactively developing and debugging Clojure code
479 | ;; ... The REPL is your friend.
480 | ;; - Learn to use lexical scope and function closures effectively.
481 | ;; - Learn to define small "single purpose" functions, such that
482 | ;; you can compose them together to produce higher order logic.
483 |
484 | ;;
485 | ;; 4clojure Drills: Problems you could try now.
486 | ;;
487 | ;; - #protip: Write the solutions as proper named functions in your code base,
488 | ;; without code-golfing or hacks. Then translate to anonymous function form
489 | ;; that 4clojure requires.
490 | ;;
491 | (comment
492 | (map (fn [problem-no] (str "https://4clojure.oxal.org/#/problem/"
493 | problem-no))
494 | [14, 15, 19, 20, 48, 45]))
495 |
--------------------------------------------------------------------------------
/tutorials/clojure-by-example/src/examples/ex03_data_and_functions.clj:
--------------------------------------------------------------------------------
1 | (ns examples.ex03-data-and-functions ; current namespace (ns)
2 | ;; "require" and alias another ns as `p`:
3 | (:require [clojure-by-example.data.planets :as p]))
4 |
5 |
6 | ;; Ex03: LESSON GOALS
7 | ;; - Explore various bits and bobs of the solution interactively
8 | ;; using the live environment at your disposal
9 | ;; - Get some ideas of how to take just a handful of pieces,
10 | ;; and build sophisticated logic with them
11 | ;; - Debug any issues that might arise
12 | ;; - We use only the concepts and standard library functions
13 | ;; we've seen so far, to build purely functional logic
14 | ;; in order to process a bunch of planets:
15 | ;;
16 | ;; - Standard Library (about 20 functions):
17 | ;; `def`, `defn`, `fn`, `let` ; to create/name simple data and small functions
18 | ;; `get`, `get-in`, `assoc` ; to query and associate data
19 | ;; `map`, `filter`, `reduce` ; to operate on collections
20 | ;; `if`, `when`, `cond` ; to decide things
21 | ;; `not`, `and`, `empty?`, `<=`, `count` ; for logic and quantities
22 | ;; `comp`, `complement` ; to glue higher-order logic
23 | ;;
24 | ;; - Concepts:
25 | ;; - Compute only with pure functions:
26 | ;; - Build higher-order logic with higher order functions
27 | ;; - Lexical scope and function closures to maximize modularity
28 | ;; - Collections as functions:
29 | ;; - Keywords as functions of hash-maps
30 | ;; - Well-defined Sets as predicates --- tests of set membership
31 | ;; - Hash-maps and collections to model domain entities:
32 | ;; - A planet, or atmospheric tolerances, or decision tables,
33 | ;; or collections of analysis criteria
34 | ;; - Truthy / Falsey logic:
35 | ;; - Instead of only Boolean true/false
36 | ;; - Namespaces:
37 | ;; - Making use of things defined elsewhere
38 | ;;
39 | ;; - Workflow:
40 | ;; - Apply the Scientific Method to design, debug, and to understand
41 | ;; - Run small fast experiments via the REPL
42 | ;; - Preserve your experiments in-line within your codebase itself
43 | ;;
44 | ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
45 | ;; Let's colonize planets!
46 | ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
47 |
48 | (comment
49 | ;; BACKGROUND
50 | ;;
51 | ;; The Office of Interstellar Affairs (OIA) is pushing hard
52 | ;; for all-out space exploration and colonization.
53 | ;;
54 | ;; The OIA intends to issue "mission directives"...
55 | ;;
56 | ;; They wish humanity to :inhabit, or :colonise, or :probe,
57 | ;; or :observe a given planet based on their analysis of
58 | ;; available planetary data.
59 | ;;
60 | ;; For a given "mission directive", like :probe, the OIA
61 | ;; intends to dispatch a collection of vessels.
62 |
63 | ;; GOAL
64 | ;;
65 | ;; Prototype a bit of planetary analysis logic, using criteria
66 | ;; that interest the OIA, such that they will be able to decide
67 | ;; what to do about a given planet.
68 | ;;
69 | ;; Criteria include questions like:
70 | ;; - co2-tolerable?
71 | ;; - gravity-tolerable?
72 | ;; - surface-temp-tolerable?
73 | ;;
74 | ;; How a planet stands up to such questions will let us assess
75 | ;; whether it is habitable? or colonisable? or observe-only?.
76 | ;;
77 | ;; Once we deliver the OIA our assessment, they may choose to
78 | ;; dispatch one or more kinds of Starfleet vessels to the planet.
79 | )
80 |
81 | ;; Here are some target planets:
82 | clojure-by-example.data.planets/target-planets
83 |
84 | ;; Which we can access more conveniently as:
85 | p/target-planets
86 |
87 | (map :pname p/target-planets)
88 |
89 |
90 |
91 | (def starfleet-mission-configurations
92 | "Associate 'mission directives' like :inhabit, :colonise, :probe,
93 | and 'mission configurations' of Starfleet vessels. e.g. If our
94 | analysis of a planet says :probe, then we would send 1 'Orbiter'
95 | class Starship carrying a complement of 100 autonomous probes."
96 |
97 | {:inhabit {:starships 5, :battle-cruisers 5,
98 | :orbiters 5, :cargo-ships 5,
99 | :probes 30}
100 |
101 | :colonise {:starships 1, :probes 50}
102 |
103 | :probe {:orbiters 1, :probes 100}
104 |
105 | :observe {:orbiters 1, :probes 10}})
106 |
107 |
108 |
109 | ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
110 | ;; Basic Planetary Analysis
111 | ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
112 |
113 |
114 | ;; Some basic constants, utility functions, and "predicate"
115 | ;; functions to test a given planet for particular conditions.
116 |
117 |
118 | (def tolerances
119 | "Define low/high bounds of planetary characteristics we care about."
120 | {:co2 {:low 0.1, :high 5.0}
121 | :gravity {:low 0.1, :high 2.0}
122 | :surface-temp-deg-c {:low -125, :high 60}})
123 |
124 |
125 | (def poison-gas?
126 | "A set of poison gases."
127 | #{:chlorine, :sulphur-dioxide, :carbon-monoxide})
128 |
129 |
130 | (defn lower-bound
131 | [tolerance-key]
132 | (get-in tolerances [tolerance-key :low]))
133 |
134 |
135 | (defn upper-bound
136 | [tolerance-key]
137 | (get-in tolerances [tolerance-key :high]))
138 |
139 |
140 | (defn atmosphere-present?
141 | [planet]
142 | (not (empty? (:atmosphere planet))))
143 |
144 | #_(map :pname
145 | (filter atmosphere-present? p/target-planets))
146 |
147 |
148 | (defn co2-tolerable?
149 | [planet]
150 | (let [co2 (get-in planet
151 | [:atmosphere :carbon-dioxide])]
152 | (when co2
153 | (<= (lower-bound :co2)
154 | co2
155 | (upper-bound :co2)))))
156 |
157 | #_(map :pname
158 | (filter co2-tolerable? p/target-planets))
159 |
160 |
161 | (defn gravity-tolerable?
162 | [planet]
163 | (when (:gravity planet)
164 | (<= (lower-bound :gravity)
165 | (:gravity planet)
166 | (upper-bound :gravity))))
167 |
168 | #_(map :pname
169 | (filter gravity-tolerable? p/target-planets))
170 |
171 |
172 | (defn surface-temp-tolerable?
173 | [planet]
174 | (let [temp (:surface-temp-deg-c planet)
175 | low (:low temp)
176 | high (:high temp)]
177 | (when (and low high)
178 | (<= (lower-bound :surface-temp-deg-c)
179 | low
180 | high
181 | (upper-bound :surface-temp-deg-c)))))
182 |
183 | #_(map :pname
184 | (filter surface-temp-tolerable? p/target-planets))
185 |
186 |
187 | (defn air-too-poisonous?
188 | "The atmosphere is too poisonous, if the concentration of
189 | any known poison gas exceeds 1.0% of atmospheric composition."
190 | [planet]
191 | (let [gas-too-poisonous? (fn [gas-key-pct-pair]
192 | (and (poison-gas? (gas-key-pct-pair 0))
193 | (>= (gas-key-pct-pair 1) 1.0)))]
194 | (not
195 | (empty?
196 | (filter gas-too-poisonous?
197 | (:atmosphere planet))))))
198 |
199 |
200 | (map :pname
201 | (filter air-too-poisonous? p/target-planets))
202 |
203 | ;; Note: a hash-map is a collection of key-value pairs
204 | (map identity
205 | {:nitrogen 78.08, :oxygen 20.95, :carbon-dioxide 0.4,
206 | :water-vapour 0.1, :argon 0.33, :traces 0.14})
207 |
208 | (map (fn [pair]
209 | (str (get pair 0) " % = " (get pair 1)))
210 | {:nitrogen 78.08, :oxygen 20.95, :carbon-dioxide 0.4,
211 | :water-vapour 0.1, :argon 0.33, :traces 0.14})
212 |
213 |
214 |
215 | ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
216 | ;; Composite checks to perform on a given planet
217 | ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
218 |
219 |
220 | (def minimal-good-conditions
221 | "A collection of functions that tell us about the
222 | good-ness of planetary conditions."
223 | [co2-tolerable?
224 | gravity-tolerable?
225 | surface-temp-tolerable?])
226 |
227 |
228 | (def fatal-conditions
229 | "A collection of functions that tell us about the
230 | fatality of planetary conditions."
231 | [complement atmosphere-present?
232 | air-too-poisonous?])
233 |
234 |
235 | (defn conditions-met
236 | "Return only those condition fns that a planet meets.
237 | An empty collection means no conditions were met."
238 | [condition-fns planet]
239 | (filter (fn [condition-fn]
240 | (condition-fn planet))
241 | condition-fns))
242 |
243 |
244 | (defn planet-meets-no-condition?
245 | [conditions planet]
246 | (empty? (conditions-met conditions planet)))
247 |
248 |
249 | (def planet-meets-any-one-condition?
250 | (complement planet-meets-no-condition?))
251 |
252 |
253 | (defn planet-meets-all-conditions?
254 | [conditions planet]
255 | (= (count conditions)
256 | (count (conditions-met conditions planet))))
257 |
258 |
259 | ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
260 | ;; Composite checks to
261 | ;; - test whether a given planet meets a variety of conditions.
262 | ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
263 |
264 |
265 | (defn habitable?
266 | "We deem a planet habitable, if it has all minimally good conditions,
267 | and no fatal conditions."
268 | [planet]
269 | (when (and (planet-meets-no-condition?
270 | fatal-conditions
271 | planet)
272 | (planet-meets-all-conditions?
273 | minimal-good-conditions
274 | planet))
275 | planet))
276 |
277 | #_(map :pname
278 | (filter habitable? p/target-planets))
279 |
280 |
281 | (defn colonisable?
282 | "We deem a planet colonisable, if it has at least one
283 | minimally good condition, and no fatal conditions."
284 | [planet]
285 | (when (and (planet-meets-any-one-condition?
286 | minimal-good-conditions
287 | planet)
288 | (planet-meets-no-condition?
289 | fatal-conditions
290 | planet))
291 | planet))
292 |
293 | #_(map :pname
294 | (filter colonisable? p/target-planets))
295 |
296 |
297 | (defn observe-only?
298 | "We select a planet for orbital observation, if it only has harsh surface conditions."
299 | [planet]
300 | (when (and (planet-meets-any-one-condition?
301 | fatal-conditions
302 | planet)
303 | (planet-meets-no-condition?
304 | minimal-good-conditions
305 | planet))
306 | planet))
307 |
308 | #_(map :pname
309 | (filter observe-only? p/target-planets))
310 |
311 |
312 |
313 | ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
314 | ;; Enrich planetary data with Starfleet mission information
315 | ;; from the Office of Interstellar Affairs.
316 | ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
317 |
318 | (defn issue-mission-directive
319 | [planet]
320 | (cond
321 | (habitable? planet) :inhabit
322 | (colonisable? planet) :colonise
323 | (observe-only? planet) :observe
324 | :else :probe))
325 |
326 |
327 | (defn assign-vessels
328 | [planet]
329 | (let [mission-directive (issue-mission-directive planet)]
330 | (assoc planet
331 | :mission-directive mission-directive
332 | :mission-vessels (mission-directive starfleet-mission-configurations))))
333 |
334 |
335 | #_(map assign-vessels p/target-planets)
336 |
337 | ;; Something's not right...The Office of Interstellar Affairs tells us we're not assigning vessels correctly?!
338 | ;; We've only deployed probes and orbiters, and no other vessels?!
339 |
340 | ;; We spent all this time and 300 lines of code to direct these vessels, and the orders aren't even correct!
341 | ;; We don't even see an error message! Clearly Clojure is the worst language ever made!
342 |
343 | ;; ...OR IS IT?
344 |
345 | (comment
346 | ;; It's time to learn how Clojure allows us to debug and understand our programs, using nothing more
347 | ;; than the REPL and our wits.
348 |
349 | ;; Let's look at our results again, shall we? Are we really only deploying probes and orbiters?
350 |
351 | (map assign-vessels p/target-planets)
352 |
353 | ;; That's a bit hard to visually parse, how about this:
354 |
355 | (map :mission-vessels (map assign-vessels p/target-planets))
356 |
357 | ;; The OIA is right! But why is this happening?
358 | ;; Either our directive to fleet mapping is wrong, or our issued directives are wrong.
359 |
360 | starfleet-mission-configurations
361 |
362 | ;; The configurations look fine. What about the directives?
363 |
364 | (map :mission-directive (map assign-vessels p/target-planets))
365 |
366 | ;; We're only probing and observing! Clearly issue-mission-directive is at fault.
367 | ;; Let's take a look at its source code again.
368 |
369 | ;; Does this mean that there are no planets which our code considers habitable or colonisable?
370 |
371 | ;; EXERCISE:
372 | ;; Check whether we have any habitable or colonisable planets according to the habitable? and colonisable? predicates.
373 |
374 | ;; Apparently we don't!
375 | ;; At the very least, the planet Earth should be both habitable and colonisable.
376 | ;; At least now we know that habitable? and colonisable? are problematic. But why? Let's look at their implementation.
377 | ;; We'll narrow in on habitable? for the time being, and worry about colonisable? later.
378 |
379 | ;; A planet is habitable iff:
380 | ;; 1. It has an atmosphere
381 | ;; 2. The air is not too poisonous
382 | ;; 3. The carbon dioxide, gravity and temperature levels are all tolerable
383 |
384 | ;; The following issues are possible:
385 | ;; 1. planet-meets-any-one-condition? is broken.
386 | ;; 2. planet-meets-no-condition? is broken.
387 | ;; 3. minimal-good-conditions is broken.
388 | ;; 4. fatal-conditions is broken.
389 | ;; 5. Any or all of the above.
390 |
391 | ;; EXERCISE: Check if planet-meets-any-one-condition? works correctly.
392 | ;; planet-meets-any-one-condition? accepts predicates as a parameter, and doesn't care about the predicates
393 | ;; themselves. Because of this, we can simplify our debugging by using simple and obvious predicates,
394 | ;; rather than using the predicates in the production code.
395 |
396 | ;; EXERCISE: Check if planet-meets-no-condition? works correctly.
397 |
398 | ;; If none of those work, clearly there's something wrong with our conditions themselves.
399 |
400 | ;; EXERCISE: Diagnose and fix the broken conditions.
401 |
402 | ;; Does everything work now?
403 |
404 | (map assign-vessels p/target-planets)
405 | )
406 |
407 | ;;
408 | ;; RECAP
409 | ;; - Hopefully, you now have a better handle on the various aspects
410 | ;; of working with Clojure, listed in the exercise goals; viz.
411 | ;; - Reading: How to explore an unfamiliar Clojure code-base _interactively_?
412 | ;; - "Primitives": How to get a lot done with just 20-odd core functions?
413 | ;; - Concepts: What helps us model our domains and compose functional logic?
414 | ;; - Workflow: How to apply the scientific method to development and debugging?
415 | ;;
416 | ;; - REPL all the things!
417 | ;; Especially understand how the Clojure REPL is a powerful debugging tool
418 | ;; that supersedes more traditional step-through debuggers in many ways.
419 | ;;
420 | ;; You can:
421 | ;; 1. Test individual functions or constants to check if they're correct.
422 | ;; 2. Redefine a function to add tracing such as print statements, or other forms of instrumentation.
423 | ;; 3. Capture intermediate values such as function arguments or let bindings, and inspect them in the REPL
424 | ;; after the fact.
425 | ;; 4. Fix the problem and verify that it works immediately.
426 | ;; 5. Do all of the above either locally, or while connected to a remote server running in a staging or
427 | ;; production environment.
428 | ;;
429 | ;; We strongly recommend going through https://clojure.org/guides/repl/enhancing_your_repl_workflow#debugging-tools-and-techniques
430 | ;; for more tips, tricks and resources related to debugging. The entire REPL guide is useful, but the section about debugging
431 | ;; is particularly pertinent.
432 |
433 | ;;
434 | ;; 4clojure Drills: Problems you could try now.
435 | ;;
436 | ;; - #protip: Write the solutions as proper named functions in your code base,
437 | ;; without code-golfing or hacks. Then translate to anonymous function form
438 | ;; that 4clojure requires.
439 | (comment
440 | (map (fn [problem-no] (str "https://4clojure.oxal.org/#/problem/"
441 | problem-no))
442 | [37, 64, 72, 21, 24, 25,
443 | 38, 29, 42, 31, 81, 107,
444 | 88, 157, 50, 46, 65]))
445 |
--------------------------------------------------------------------------------
/web/echo-server/.idea/dbnavigator.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
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 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
389 |
390 |
391 |
392 |
393 |
394 |
395 |
396 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 |
405 |
406 |
407 |
408 |
409 |
410 |
411 |
412 |
413 |
414 |
415 |
416 |
417 |
418 |
419 |
420 |
421 |
422 |
423 |
424 |
425 |
426 |
427 |
428 |
429 |
430 |
431 |
432 |
433 |
434 |
435 |
436 |
437 |
438 |
439 |
440 |
441 |
442 |
443 |
444 |
445 |
446 |
447 |
448 |
449 |
450 |
451 |
452 |
453 |
454 |
455 |
456 |
457 |
458 |
459 |
460 |
461 |
462 |
463 |
464 |
465 |
466 |
467 |
468 |
--------------------------------------------------------------------------------