Socratic Clojure

See related: [Notebook] Symbols in Code and Clojure What are all these different symbols (such as "#", "_", "@", etc.) called in general? In Clojure? What do they mean/indicate?

{:deps {org.clojure/clojure {:mvn/version "1.10.3"}
        ;; complient is used for autocompletion
        ;; add your libs here (and restart the runtime to pick up changes)
        compliment/compliment {:mvn/version "0.3.9"}}}
Extensible Data Notation
{:hello (clojure-version)}
0.1s

How to do "Hello World" in Clojure

;; All "forms"/"expressions" in Clojure are wrapped in parentheses ("parens" for short)
;; The first item in a parens is the "function" spot, and all subsequent items are the argumments (also called "args" as in other languages) - this is the syntax for the whole language!*
;; This line below evaluates the function call "print line" with the single string literal argument "Hello World"
;; *There are some special exceptions such as reader macros, special characters, etc..
(println "Hello World")
0.4s

How to define global variables ("bindings")

;; global bindings
(def my-age 5) ;; ("define key word" "binding name" "value to be bound")
(println my-age)
0.4s

How to define local bindings

;; lexically scoped variables
(let [my-name "Hikaru"
      my-fav-color :blue ;; keywords are prefaced with colons
      my-fav-food 'pizza] ;; symbols are prefaced with single quotes
  (println (str "Hi " my-name "!"))
  (println (str "Oh, I see you like " my-fav-food
             " and the color " my-fav-color ".")))
;; demo that my-name is no longer in scope, therefore we can no longer access the value bound in the above let
;; (println my-name) ;; => nil
0.5s

Q: What does the str (can be pronounced "stir" or "struh" or "string") function do?

;; str does both string concatenation and type-casting
(def concatted-string (str "Sand" "witches"))
(def val-casted-to-str-1 (str true))
(def val-casted-to-str-2 (str 5))
(def val-casted-to-str-3 (str [1 2 3]))
(println concatted-string)
(map println [val-casted-to-str-1 val-casted-to-str-2 val-casted-to-str-3])
0.4s

How to define a basic function?

;; basic function definition
(defn add-5
  "adds 5 to whatever number is passed in"
  [x]
  (+ x 5))
0.0s

How to invoke a user-defined ("custom") function?

;; function invocation
(println (add-5 7))
0.4s

How to define a recursive function

;; recursive function, factorial
(defn fact [n]
  (if (= n 1)
    1
    (* n (fact (dec n)))))
(println (fact 5)) ;; => 120
0.4s

How to "do" error handling

  • (TODO: be more specific between various distinct, meaningful, & relevant use-cases of error handling)

How to catch errors generally

  • (TODO: extract `finally` example to separate "how to")

;; error handling
;; (println (/ 5 0)) ;; => Divide by zero error/exception
(try
  ;; "protected code block"
  (println (/ 5 0))
  (catch
    ;; "catch block"
    Exception e (println (str "caught exception: " (.toString e))))
  (finally (println "--> This gets printed no matter what happens in the try-catch.")))
;; Note: Typically, Clojure code-bases tend to not use try-catches very much. Instead, Clojure code tends to return "nil" (nothing), upon "failure" (TODO: clarify what is meant by "failure").
0.4s

How to catch a specific exception with precision

(try
  (println (/ 3 0))
  ;; note: both `java.lang.ArithmeticException e` and `ArithmeticException e` appear to work in the catch block (expression? . This would lend evidence to the idea that Clojure can infer (and/or look up) available Java exceptions (exception types? types of exceptions?), as well as the idea that different libraries/namespaces may hold exceptions of the same name but with different functionality/design for different needs/purposes/situations. 
  (catch ArithmeticException e
    ;; Q: Must we use Java interop .toString here, or is there a reason why it is preferred to other alternatives? Is there a built in Clojure way to cast exceptions to a human readible string?
    (println (str "caught Arithmetic Exception: " (.toString e)))))
;; java.lang.ArithmeticException: Divide by zero
0.4s

How to create ratios

(def my-number 13/7) ;; Q: Does the ratio 13/7 employing function calls "under the hood"?
(println my-number)
(println (type my-number))
0.4s

How to rebind (redefine?) global variables (note: this is considered "dangerous")

Q: Why use global def rebinding? A: For example, when used as a debugging technique, "redef"-ing as such can be convenient for inspecting intermediate values, for "scope capture", where API calls are made, or state changes happen, and the developer is interested to inspect the "before" and "after" "states".

;; Since my-number was already defined/bound up above, this next line demonstrates that we can rebind/redefine my-number as a string (this implies (proves? demonstrates? lends evidence to the understanding that?) that Clojure is not statically typed)
(def my-number "thirteen over seven")
(println my-number)
(println (type my-number))
0.4s

How to chain functions(/methods?/operations?) with the thread-first macro (->)

;; thread-first and thread-last are great for passing data through a series of functions
;; for example, let's take the following sentence which includes words, punctuation, and spacing, and convert it into an acronym. Note that, in the examples below, the three commas are written to show where the thread-first and thread-last macros will "pass through" data, though the commas themselves will be ignored by the Clojure reader.
(def sentence1 "Red, orange, yellow, green, blue, indigo, violet.")
(def sentence2   (-> sentence1
                  (clojure.string/replace ,,, #"[,.]" "") ;; remove unwanted chars
                   (clojure.string/split #" ") ;; split into sequence of words
                   ;; (#(map first %))  ;; if it were necessary, we **could** do this, but see below for a more readable alternative
                  ))
0.1s

How to chain functions(/methods?/operations?) with the thread-last macro (->>)

(->> sentence2
  (map first ,,,) ;; grab the first letter of each word
  clojure.string/join ,,, ;; convert the list of strrings back into a single string
  clojure.string/upper-case) ;; conver the entire string to all upper-case
0.0s

How to process data with thread macros in a "flatter", more readable (ie. low cognitive complexity / cognitive load) way

(defn acronym [s]
  ;; note: Commas are ignored by the Clojure interpreter, so, they are simply here to illustrate for academic purposes how "the data flows through" function to function
  (let [;; thread-first macro usage
        no-punc-split (-> s ;; typically used on singular items
                        (clojure.string/replace ,,, #"[,.]" "") ;; remove unwanted chars
                        (clojure.string/split ,,, #" ")) ;; split into sequence of words
        ;; thread-last marco usage (typically used on collections)
        final-result (->> no-punc-split
                       (map first ,,,) ;; grab the first letter of each word
                       (clojure.string/join ,,,) ;; convert the list of strrings back into a single string
                       clojure.string/upper-case) ;; conver the entire string to all upper-case
        ]
    final-result))
(acronym "Domain, kingdom, phylum, clase, order, family, genus, species.")

How to use the # pound symbol (also called an octothorpe) in Clojure for anonymous function shorthand

;; the percent sign % is the first parameter/argument passed to the anonymous function, it could also be written as %1
#(+ 3 %) ;; This expression is equivalent to (fn [x] (+ 3 x)), but just by itself, it doesn't serve much purpose, since we aren't passing any arguments to it
(#(+ 3 %) 5) ;; to make use of an anonymous function, we can immediately invoke it by wrapping it in parens and passing it zero or more arguments (though, come to think of it, I can't remember the last time I saw an anonymous function with zero arguments...
;; Q: What, if any, are typical/common/practical use-cases for anonymous functions with no arguments?) 
0.0s

How to make set literals in Clojure with the # symbol (and correctly identify sets as a data structure in Clojure)

;; Note: Sets in Clojure do NOT gaurentee order! If order matters, instead use a sorted-set.
(println #{42 777 25}) ;; Like hashmaps, sets in Clojure are wrapped with curly braces / brackets. Unlike hashmaps, sets are prefixed with the # pound sign.
;; note: We can also make sets in Clojure by using the set function like so:
(set [1 3 9 27 81])
;; Observe that sets are printed by default with the # pound sign to clearly distinguish them from hashmaps.
0.4s
;; I was looking at the wiki and it gave me a few topics for further investigation[:]
;; lists vs vectors, something that looks like a chaining operator
;; #, @, and _ symbols
;; We did, btw, in this order: basic lisp syntax, global variables, local/lexical variables / scoping, basic function definitions, function invocations, recursive functions, "Are Clojure/ClojureScript dynamically or statically typed?", "What are dynamic and static typing in Computer Science?", "What are the differences between Clojure and ClojureScript data type implementations?"\*, error handling in Clojure/ClojureScript\*\*, and next, but we didn't get to go into it together, "What are the diffs between vectors and lists in Clojure/ClojureScript?"   
0.0s

Questions

;; Q: What in Clojure allows us to use fractions as a built-in type? eg. dynamic typing, statically typing, floating point or stored as a fraction type
;; A: Clojure uses ...
;; Q: What's the diff between lists and vectors in Clojure(/Script)?
0.0s

Notes

;; Notes
;; - Static typing is where types are inferred or explicitly set and types are immutably set (though children/sub/nested types may still be mutable/changable)
;; - Dynamic typing allows the changing of types on the fly, such as JavaScript, Python, and PHP
;; - Type inference is not related to dynamic/static typing
0.0s

Demos I Want to Make Next

;; demo all the exceptions
;; for reference / further inspiration: https://www.geeksforgeeks.org/types-of-exception-in-java-with-examples/
;; (catch java.io.FileNotFoundException e (println (str "caught file exception: " (.getMessage e))))
;; out of bounds error (try to access an index that doesn't exist, such as index 5 for a sequence of size 3, or index -5 which should be invalid)
;; stack overflow error (try to run code that uses up too much memory)
;; type mismatch error (try to subtract one string from another)
;; ... other possible Clojure errors/exceptions?
Runtimes (1)