Clojure Koans 1 Equality Remix
TL;DR: Welcome to my first remixed notebook highlighting the Clojure Koans. See bottom of this document for my reason for remixing ramble 😉
What this notebook is for
As in the original notebook, I'll break down, solve, and investigate the Clojure Koans to better understand Clojure. I hope the "micro-skills" that I find will be useful for Clojure learners.
Please follow along with me in my journey, attempt to answer the questions I pose, ask new questions I haven't thought of, or propose new "skills".
Your feedback is crucial to making these notebooks awesome!
Original Koans repo is here: https://github.com/functional-koans/clojure-koans/
Spoilers Alert!
I share my answers for each Koan exercise ("meditation") below. If you are new to Clojure and want to attempt these for yourself, I urge you to come back after you have spent a little time on them.
Format
For each exercise I include:
my answer to the Koan exercise
one or more relevant skills (numbered in the order I find them)
one or more questions (numbered in the order I think of them)
Note: For each notebook, I will prefix skills and questions w/ the notebook number times 1000, so that way there will be room for 999 skills and questions per section... Yep, that should be enough.
;; configurations (don't edit this block)
{:deps {org.clojure/clojure {:mvn/version "1.10.1"}
;; complient is used for autocompletion
;; add your libs here (and restart the runtime to pick up changes)
compliment/compliment {:mvn/version "0.3.9"}}}
Statement 1001: deps.edn is the common way in 2023 to manage Clojure project dependencies. [source missing]
Statement 1002: Before deps.edn, Leiningen ("Lein") was the most commonly used dependency management tool, where, rather than a deps.edn file, a project.clj file was used instead. [source missing]
;; configurations test, this is Nextjournal specific, to confirm
;; that this notebook's version of Clojure is 1.10.1 or greater
{:hello (clojure-version)}
;; Koan 1001
;; "We shall contemplate truth by testing reality, via equality"
(= true true)
Skill 1001: You can compare two or more things using the `=` "equality" function. Source of function's name: https://clojuredocs.org/clojure.core/=
Question 1001: What are the smallest individual pieces/parts/items in Clojure syntax called? Are they names, symbols, tokens, entities, or something else? For example, is there an umbrella term which encapsulates both `=` and `true`?
Statement 1013: [answer to question 1001] The smallest individual pieces of Clojure syntax are tokens. Tokens make up expressions (which always evaluate to something) and special forms (which don't have the same guarantee as expressions). Source: ChatGTPT https://shareg.pt/zsg6ohY , WikiBooks "Learning Clojure" https://en.wikibooks.org/wiki/Learning_Clojure/Special_Forms [TODO: validate this answer]
Skill 1011: You can evaluate Clojure code in Nextjournal by either clicking the triangle "run cell" button in the upper-right hand corner of a cell, or, by hitting Ctrl+Enter to evaluate the currently focused cell.
Statement 1003: Equality `=` is a plain function in Clojure, and isn't using special operator syntax. [source missing]
Statement 1004: `true` is a primitive value literal. [source missing]
;; Koan 1002
;; "To understand reality, we must compare our expectations against reality"
(= 2 (+ 1 1))
(clojure.repl/doc =)
Skill 1002: You can add/sum two or more numbers together using the +
addition function.
Skill 1010: You can nest forms/expressions inside of each other.
;; Koan 1003
;; "You can test equality of many things"
(= (+ 3 4) 7 (+ 2 5))
(swap! koan-tree assoc
1003 {:type "skill"
:text "add/sum two numbers together using the `+` addition function"})
;; Koan 1004
;; "Some things may appear different, but be the same"
(= true (= 2 2/1))
Statement 1005: Whole numbers and ratios can be compared with each other in Clojure with the "strict equality" = function, because, rather than Java numerical "types" mattering for the sake of comparability, matching one of the three number "categories" is what matters instead: Either of integers and ratios, or of floats and doubles, or, lastly by itself, BigDecimal. Source: https://clojure.org/guides/equality
;; Koan 1004
;;"You cannot generally float to heavens of integers"
(= false (= 2 2.0)
Statement 1006: Comparing an integer and decimal precision number of equal value in Clojure gives a result of false
when using `=`, as Clojure's `=` uses strict equality to compare items by number "category" as stated (above) in statement 1005. Source: https://clojure.org/guides/equality
Statement 1007: Equal value float/decimal precision numbers and integers are considered equivalent in ClojureScript [demo below], due to JavaScript's underlying implementation of numbers.
Statement 1008: Equality is calculated by value, not by identity, in Clojure. Source: https://clojuredocs.org/clojure.core/=
Question 1002: What is the plain English name for the "double equal sign" (==) function in Clojure? If it has no name, why is that so? Research: https://clojuredocs.org/clojure.core/==
Answer to question 1002....
Skill 1003: You can compare numerical equality regardless of numerical "category" in Clojure using the ==
function
;; demo for Statement 1006
(= 2 2.0) ; false in Clojure
;; demo for Statement 1007
(= 2 2.0) ; true in ClojureScript
(swap! koan-tree assoc
1004 {:type "skill"
:text "Compare numerical equality irregardless of type using the `==` function"})
;; Koan 1005
;; "But a looser equality is also possible"
(= true (== 2.0 2))
Question 1003: What are typical use-cases for non-strict equality?
Statement 1009: [ChatGPT answer to question 1003] [TODO: validate this statement] "Some use-cases where non-strict equality might be used include:
Comparing values that may be of different data types, such as when comparing user input with a known value.
When checking for the presence of a value in an array or object, where the type of the value may not be known in advance.
When comparing variables that may contain different types of data at different points in the program's execution."
Source: ChatGPT https://shareg.pt/9GQkW49
;; Koan 1006
;;"Something is not equal to nothing"
(= true (not (= 1 nil)))
Skill 1004: You can convert something that is false to true and vice-versa using the `not` function
(swap! koan-tree assoc
1005 {:type "skill"
:text "Convert something is true to false and vice-versa using the `not` function"})
;; Koan 1007
;;"Strings, and keywords, and symbols: oh my!"
(= false (= "hello" :hello hello))
Question 1004: What are the typical use cases for keywords in Clojure?
Statement 1010: [answer to question 1004] Keywords are typically used as map keys ( such as
:age
or:id
), configuration keys (such as:require
), enumerated values (such as#{:red :blue :green}
) or map destructuring (such as(let [{:keys [age name nationality]}])
). [source missing] ~ Avi
Question 1005: What are the typical use cases for symbols in Clojure?
Statement 1011: [answer to question 1005] Symbols are typically uses as names to bind values, functions, and objects to. Some examples are
(def name "Avi")
where `name` is a symbol, and(defn add [x y] (+ x y))
where there are 5 symbols:defn
,add
,x
,y
, and+
. When symbols are evaluated in the REPL, are prefixed by an octothorpe and a single quote like so#'add
.
;; Demo block for statement 1012
(defn add [x y] (+ x y)) ;; define a var & bind a function to it
(def my-age 35) ;; define a var & bind a value to it
(println (symbol? add)) ;; syntax check: is 'add a symbol?
(println add) ;; what does
(println add)
;; Note: Bear in mind that because vars are interned (and saved)
;; in this document once a code cell has been run. In order to
;; see the effects of commenting out a line and re-running the
;; code, please restart the entire notebook runtime.
Question 1006: What are the most generalized pieces of syntax in Clojure, that everything in Clojure is made up of? Which of these are valid/accepted vocab; forms, tokens, expressions, symbols, entities, statements? (note: This is similar to, but not the same as, question 1001) [TODO: assess if this is an answerable/valid question]
Statement 1015: [answer to question 1006] Clojure, as a Lisp, is made up entirely of lists, with zero or more tokens inside of them. Nothing, as far as I can tell, in Clojure, is (syntactically speaking) neither a list nor a non-list token. [source missing]
Question 1009: What is the relationship hierarchy between these things in Clojure: forms and expressions, vars and bindings, and symbols and names?
Answer to question 1009: https://clojureverse.org/t/differences-between-names-and-symbols-vars-and-bindings-forms-and-expressions/9844/1
;; Koan 1008
;;"Make a keyword with your keyboard"
(= :hello (keyword "hello"))
Skill 1005: You can write/create a keyword literal using the :
colon prefix. Source: https://clojure.org/guides/weird_characters#_keyword
Skill 1006: You can create a keyword from a string using the keyword
function. Source: https://clojure.org/guides/weird_characters#_keyword
(swap! koan-tree assoc
1006 {:type "skill"
:text "Write/Create a keyword literal using the `:` colon prefix"}
1007 {:type "skill"
:text "Create a keyword from a string using the `keyword` function"})
;; Koan 1009
;;"Symbolism is all around us"
(= hello (symbol "hello"))
Skill 1007: You can write/create a symbol literal using the '
single quote prefix
Question 1007: What is the (') single quote prefix called in Clojure? [glossary vocabulary terminology]
Statement 1012: (answer to question 1007) The single quote symbol is simply referred to as "quote". Source: https://clojure.org/guides/weird_characters#_quote
Skill 1008: You can create a symbol from a string using the symbol
function
(swap! koan-tree assoc
1008 {:type "skill"
:text "Write/Create a symbol literal using the `'` single quote prefix (?)"}
1009 {:type "skill"
:text "Create a symbol from a string using the `symbol` function"})
;; Koan 1010
;;"What could be equivalent to nothing?"
(= nil nil)
Question 1008: What exactly is nil
in Clojure? (is it a type?, is it a symbol?, what category of "things" does it belong to?, etc.) [glossary vocabulary terminology]
Statement 1014: [answer to question 1008] [chatGPT answer]
nil
is a primitive value, and not a type, in Clojure. Source: https://shareg.pt/15Ef23p [TODO: validate this answer]
;; Koan 1011
;;"When things cannot be equal, they must be different"
(not= :fill-in-the-blank :blah)
Skill 1009: You can compare for inequality using the not=
function
2023_02_28 Ramble
Back in 2021, as an academic exercise, I went through the Clojure Koans, attempting to understand as much as I could. I had a lot of questions, some of which I could answer, and some which, either I couldn't due to time constraints, or couldn't do to lack of deep Clojure expertise. After working now for a couple years in the Clojure world, I hope to try and illuminate some more insights into how Clojure works. As remixing old content of mine is not something I often do in a public space, this will be something of an experiment in writing, knowledge sharing, and public learning.
P.s. Remixing this notebook turned into a much longer activity than I anticipated. A few hours and coffees later, well, this is what we have. I'd love to hear your feedback on the reading experience, suggestions for improvement, questions, etc..
Update (2021_05_02):
I'm experimenting with creating a hybrid tree of skills, questions, and facts.
To-Do:
[ ] Create a hierarchy of nodes where each node can have one or more prerequisite nodes, and there are three types of nodes: skills, questions, and facts, where facts can be answers to questions or simply just statements (all facts come with examples & sources to back them up)