Clojure
Information
Installation
nano install-clojure.sh && chmod a+x install-clojure.sh
#!/bin/sh
curl -L -O https://github.com/clojure/brew-install/releases/latest/download/posix-install.sh
chmod +x posix-install.sh
sudo ./posix-install.sh --prefix /opt/clojure
sudo dnf install rlwrap
exit 0
nano hello.clj
(println "Hello, World!")
nano hello.sh && chmod a+x hello.sh
#!/bin/sh
clojure -Sdeps '{:deps {org.clojure/clojure {:mvn/version "1.11.1"}}}' -M hello.clj
exit 0
Configuration
Usage, tips and tricks
Prepare project
Clojure Spring Boot Execution
mvn spring-boot:run -Dspring-boot.run.arguments="-n info.setmy.main -s info/setmy/main.clj -m default-main"
java -jar .\target\clojure-0.0.0-SNAPSHOT.jar -n info.setmy.main -s info/setmy/main.clj -m default-main
Clojure maven plugin run
mvn clojure:run
Programming
; integer
42
; floating point (double)
-1.5
; ratio
22/7
; string
"hello"
; character
\e
; regular expression
#"[0-9]+"
; symbol
map
; symbol - most punctuation allowed
+
; namespaced symbol
clojure.core/+
; clojure.lang.Symbol
(type 'xyz)
; clojure.lang.Keyword
(type ':xyz)
; null value
nil
; booleans
true
false
; keyword
:alpha
; keyword with namespace
:release/alpha
; clojure.lang.Keyword
(type :a)
; clojure.lang.BigInt
(type 123N)
(type (bigint 123))
; java.math.BigInteger
(type (biginteger 123))
; vector
[1 2 3]
; list. At the case execute function 1 with params 2 and 3
(1 2 3)
; hash-map
{}
; set
#{}
Collections
Lists
Linked list.
Clojure functions calls are lists.
;; To initiate list with values use ' character. Othervise it is executed (read an interpreted) as function 1 with args 2 and 3.
;; ' is macro
;; clojure.lang.PersistentList
(type (quote (1 2 3)))
(type '(1 2 3))
(type (list 1 2 3))
(println (str '(1 2 3)))
Link: Lists
Vectors
Sequential, 0-base indexed.
;; clojure.lang.PersistentVector
(type [1 2 3])
(println (str [1 2 3]))
Link: Vectors
Sets
Unordered collection with unique vales in it.
;; clojure.lang.PersistentHashSet
(type #{:a :b :c})
(type (hash-set 1 2 3 4))
(println (str #{:a :b :c}))
(println (str (hash-set 1 2 3 4)))
(println (str {"firstName" "Imre" "lastName" "Tabur"}))
;; #{2.0 1 true "abc" 3 2}
(hash-set 1 2 3 "abc" true 2.0 "abc")
;; Syntax error reading source at (REPL:1:30).
;; Duplicate key: abc
#{1 2 3 "abc" true 2.0 "abc"}
Link: Set
Maps
;; clojure.lang.PersistentArrayMap
(type {:a 1 :b 2})
(println (str {:a 1 :b 2}))
Link: Maps
Namespaces
;; clojure.lang.PersistentArrayMap
{:person/first "Han"
:person/last "Solo"
:person/ship {:ship/name "Millennium Falcon"
:ship/model "YT-1300f light freighter"}}
Link: Maps
Symbols
;; clojure.lang.Symbol
(type 'abcDEF)
(def plusFuncSymbol '+)
(eval (list plusFuncSymbol 1 2 3))
(def listFunc (list plusFuncSymbol 1 2 3))
(eval listFunc)
Equality
;; true
(= 2 (+ 1 1))
;; false
(= 2 2.0)
;; true
(== 2 2.0)
;; java.lang.Boolean
(type (= 2 (+ 1 1)))
Functions
(defn greet [name] (str "Hello, " name))
;; This is equivalent as with anonymous function
(def greet (fn [name] (str "Hello, " name)))
(defn messenger
([] (messenger "Hello world!"))
([msg] (println msg)))
(defn hello [greeting & who]
(println greeting who))
(greet "Ernie")
(messenger)
(messenger "Hello class!")
(hello "Hello" "world" "class")
Anonymous Functions
;; Just example syntax
(fn [message] (println message))
((fn [message] (println message)) "Hello world!")
;; Equivalent to: (fn [x] (+ 6 x))
#(+ 6 %)
;; Calling that
(#(+ 6 %) 1)
Let
; 1
(let [x 1]
x)
; 3
(let [a 1
b 2]
(+ a b))
; 8
(let [c (+ 1 2)
[d e] [5 6]]
(-> (+ d e) (- c)))
; "1 2 3 4"
(let [aList (list 1 2 3 4)
[a b c d] aList]
(str a " " b " " c " " d))
misc
(-> "Look "
(str "I'm ")
(str "writing ")
(str "clojure."))
(def makeList
(->> (range 1 10)
(map println)))
(def makeList
(->> (range)
(map inc)
(take 5)))
; Exactly this way
makeList
(->> (range 1 10)
(map (fn [x] (println x) x))
(take 4))
; "2022-11-13T19:29:40.944111600Z"
(str (java.time.Instant/now))
; "2022-11-13T21:30:41.775844700"
(str (java.time.LocalDateTime/now))
(str (bean (java.time.LocalDateTime/now)))
; #inst "2022-11-13T19:29:52.015-00:00"
(java.util.Date.)
; Func passing and executing
(defn greet [value infunc] (str "Hello," (infunc value)))
(greet 2 (fn [x] (+ x 1)))
; 13.7
(get ["a" 13.7 :foo] 1)
; Filter, map, reduce
(def aVector [1 2 3 4 5 6 7 8 9])
(take 2 (map (fn [x] (* x 2)) (filter (fn [x] (= (rem x 2) 0)) aVector)))
(take 2 (map (fn [x] (* x 2)) (filter (fn [x] (= (rem x 2) 0)) aVector)))
(take-last 2 (map (fn [x] (* x 2)) (filter (fn [x] (= (rem x 2) 0)) aVector)))
; filter in even numbers from vector,map by multiplying by 2 and collect last 2 and collect into vector and sum the vector
(reduce +
(into []
(take-last 2 (map (fn [x] (* x 2)) (filter (fn [x] (= (rem x 2) 0)) aVector)))))
; Filtering hash map items list
(def person1 {:firstName "Joe" :lastName "Biden"})
(def person2 {:firstName "Donald" :lastName "Trump"})
(def person3 {:firstName "Barack" :lastName "Obama"})
(def personList (list person1 person2 person3))
(filter #(not= (:firstName %) "Joe") personList)
(remove #(= (:firstName %) "Joe") personList)
(filter #(not= "Joe" (get % :firstName)) personList)
(filter (fn [person] (not= (person :firstName) "Joe")) personList)
(filter (fn [person] (not= (get person :firstName) "Joe")) personList)
(filter #(not= (% :firstName) "Joe") personList)
(def strings ["1" "2" "3"])
; Mapping vector through mapping lambda to clojure.lang.LazySeq.
(println (map #(Integer. %) strings))
(def aVariable (conj #{} "Hello"))
; #{"World" "Hello"}
(conj aVariable "World")
; Better printout format
(println "Some object:" (pr-str some-object))
(ns my.lib.core
(:import [org.apache.logging.log4j LogManager]))
(def log (LogManager/getLogger (str (ns-name *ns*))))
(defn foor []
(.info log "Info message"))
Link: Functions
The thread-first macro (->)
Linear flow of calls for readability.
-> thing
Function composition
Make it work:
(defn double [x] (* 2 x))
(defn add-one [x] (+ 1 x))
(defn double-and-add-one (comp add-one double))
(double-and-add-one 3)
See also
- Clojupyter
- Neanderthal
- ClojureCL
- ClojureCUDA
-
Fluokitten
- 1 - component and 2 - integrant (mount - NO)
- aero
- 1 - ring, 2 - pedestal bidi (reititi, compojure)
- clj-http
- 1 - clojure.spec, 2 - schema (malli - NO)
- next.jdbc, HikariCP, HugSQL and HoneySQ
- kondo cach, kondo memoise (claypool - NO)
-
cljfmt - formatter , clj-kondo (linter)
Init deps : mount (NO), 1 - component and 2 - integrant. Config : configurati (NO), 1 - aero server: Jetty + 1 - ring, 2 - pedestal, bidi, reitit, compojure Http client: clj-http Validation : 2 - schema, 1 - clojure.spec or malli (NO) SQL: next.jdbc, HikariCP, HugSQL and HoneySQLclaybool (NO) Libs : kodo cach, *-memoise, claybool. Tools: cljfmt , clj-kondo (linter) and babashka Clojure: Liberator, Yada
IDE
- IntelliJ
- Cursive (Need to puy)
- Clojure-Kit
- VSCode - Calva