{:check ["true"],
 :rank ["expressions" "top-level" "lambda-fn" "let" "references"]}
42
[1 2 3]
+
Lists are evaluated as computation.
(+ 1 2)
(concat [1 2] [3 4])
Clojure encourages variadic arguments to functions. Most built-in functions take flexible number of arguments.
(+ 1 2 3 4 5)
(+)
Predicates are just functions returning boolean values.
(< 2 5)
(< 5 2)
(= 5 2)
(< 0 1 2)
(< 0 2 1)
(not (< 0 2 1))
Since lists can nested anywhere, we can embed computation inside data expressions.
{:title (str "CSCI" "3055U")
 :year (inc 2019)
 :total-quizzes (- (+ 2 8) 3)}
(def <name> <value>)(def pi 3.1415)
(def r 5)
(println "Area is" (* pi r r))
(format "Area is %.2f" (* pi r r))
(fn [ <arguments>... ]
  <body-expression>)(fn [r] (* 3.1415 r r))
Let's bind the area function to a global symbol, so we can use it.
(def area (fn [r] (* 3.1415 r r)))
(area 5)
(area 6)
There is a special form to make it easier.
(defn <function-name>
    [ <arguments>... ]
    <body-expression>)
(defn area [r] (* 3.1415 r r))
(area 5)
Not all symbols are at the top level. In fact, most symbols are not at top level. We can have local bindings using the form:
(let [<symbol> <expression>
      <symbol> <expression>]
    <body-expression>
    <body-expression>
    ...)
(let [first-name "Albert"
      last-name "Einstein"]
    (format "%s %s" first-name last-name))
; Outside the (let ...) form, the symbol bindings are "gone".
(format "%s %s" first-name last-name)
Let's do some more complex computation using
nested (let ...) local symbol bindings.
; - pprint is "pretty print"
; - We construct a hash-map using nested (let ...)
(clojure.pprint/pprint
 (let [first-name "Albert"
      last-name "Einstein"]
    {:first first-name
     :last last-name
     :biography (let [occupations ["Patent Clerk" "Physicist"]]
                    (str first-name " " last-name
                         " worked many jobs: "
                         (clojure.string/join " and " occupations)))}))
;