From Java To Clojure- Adieu Java -
Self-introduction
/laʒenɔʁɛk̃/lagénorhynque(defprofile lagénorhynque :name "Kent OHASHI" :account @lagenorhynque :company "Opt, Inc." :languages [Clojure Haskell Python Scala English français Deutsch русский] :interests [programming language-learning mathematics])
Lisp × Java
Java as a language
Problems with Java as a language
lack of functional programming (FP) support
More FP! (OOP and static typing are not necessary)
verbose syntax
More simplicity!
lack of �exibility/extensibility
More freedom!
JVM language comparisonfrom my own point of view
factor Java Groovy Scala Kotlin Clojure
FP support × △ ◯ △ ◯
simplicity × ◯ △ ◯ ◎
�exibility × ◯ ◯ ◯ ◎
Using Clojure,
we can say goodbye to Java as a language!!
Adieu, Java !Now we have to say farewell to you, Java (;_;)/~~~
What is Clojure?
Origin of the name Clojure
Clojure is pronounced exactly like closure, wherethe s/j has the zh sound as in azure, pleasure etc.
The name was chosen to be unique. I wanted toinvolve c (c#), l (lisp) and j (java).
Once I came up with Clojure, given the pun onclosure, the available domains and vast emptiness
of the googlespace, it was an easy decision.
― Rich Hickey, creator of Clojure
cf. meaning and pronunciation of Clojure
Clojure /ˈkloʊʒɚ/* NOT /ˈkloʊd͡ʒɚ/
element meaning
/ˈkloʊʒɚ/ closure, functional programming
C C#(.NET) as a platform, .NET language
l Lisp dialect
j Java as a platform, JVM language
1. Clojure as a FP language
2. Clojure as a Lisp dialect
3. Clojure as a JVM language
Clojure as a FP language
Immutable List, Vector, Map, Set, etc.
user=> '(1 2 3) (1 2 3)
user=> [1 2 3] [1 2 3]
user=> {:a 1 :b 2 :c 3} {:a 1, :b 2, :c 3}
user=> #{1 2 3} #{1 3 2}
Higher-order functions(filter, map, reduce, etc.)
user=> (def xs [1 2 3]) #'user/xs
user=> (filter odd? xs) (1 3)
user=> (map #(* % %) xs) (1 4 9)
user=> (reduce + 0 xs) 6
user=> (reduce + 0 (map #(* % %) (filter odd? xs))) 10
user=> (->> xs #_=> (filter odd?) #_=> (map #(* % %)) #_=> (reduce + 0)) 10
BTW,
#( ) is
#(* % %)
↓↓↓(fn [x] (* x x))
a reader macro equivalent as above.
BTW,
->> is
(->> a (f x) (g y) (h z))
↓↓↓(h z (g y (f x a)))
a macro (a kind of threading macros) expanded as above.
Lazy sequences
user=> (def nats (iterate inc 0)) #'user/nats
user=> (take 10 nats) (0 1 2 3 4 5 6 7 8 9)
user=> (take-while #(< % 10) nats) (0 1 2 3 4 5 6 7 8 9)
Clojure as a Lisp dialect
S-expressions
(f a b c ...)
f: function, macro, special forma, b, c, ...: arguments
cf. Java
f(a, b, c, ...)
Even a function/method de�nition
// Java public void greet(String name) { System.out.println("Bonjour, " + name + " !"); }
is an S-expression.
;; Clojure (defn greet [name] (println (str "Bonjour, " name " !")))
Even namespace/package declaration and imports
// Java package demo_app;
import java.io.IOException; import java.util.ArrayList; import java.util.List;
are S-expressions.
;; Clojure (ns demo-app.core (:import (java.io IOException) (java.util ArrayList List)))
first(≒ car), rest(≒ cdr), cons, ...
user=> (def xs [1 2 3]) #'user/xs
user=> (first xs) 1
user=> (rest xs) (2 3)
user=> (cons 0 xs) (0 1 2 3)
S-expression code can be treated as data(code as data; )homoiconicity
user=> (first '(def xs [1 2 3])) def
user=> (rest '(def xs [1 2 3])) (xs [1 2 3])
user=> (cons 'def '(xs [1 2 3])) (def xs [1 2 3])
user=> (eval (cons 'def '(xs [1 2 3]))) #'user/xs
Lisp macrospowerful compile-time metaprogramming facility
user=> (defmacro unless ; just a reimplementation of clojure.core/if-not macro #_=> ([test then] #_=> `(unless ~test ~then nil)) #_=> ([test then else] #_=> `(if (not ~test) #_=> ~then #_=> ~else))) #'user/unless
user=> (unless (= 1 2) :ok) :ok
user=> (macroexpand '(unless (= 1 2) :ok)) (if (clojure.core/not (= 1 2)) :ok nil)
BTW,
defn used for function de�nition
user=> (macroexpand #_=> '(defn greet [name] #_=> (println (str "Bonjour, " name " !"))))(def greet (clojure.core/fn ([name] (println (str "Bonjour, " name " !")))))
is a macro composed of def, fn special forms.
Hard to handle a lot of parentheses?
⇒ Lisp-editing plugins make it very comfortable
The Animated Guide to Paredit
Parinfer - simpler Lisp editing
Clojure as a JVM language
Compiling to Java class �lesexecutable as a jar
$ lein new app demo-app Generating a project called demo-app based on the 'app' template.
$ cd demo-app/
$ lein uberjar Compiling demo-app.core Created /Users/lagenorhynchus/code/demo-app/target/uberjar/demo-app-0.1.0-SNAPSHOT.jar Created /Users/lagenorhynchus/code/demo-app/target/uberjar/demo-app-0.1.0-SNAPSHOT-standalone.jar
$ java -jar target/uberjar/demo-app-0.1.0-SNAPSHOT-standalone.jar Hello, World!
Calling Java methods
static methods
// Java Integer.parseInt("123")
;; Clojure (Integer/parseInt "123")
instance methods
// Java "a b c".split("\\s")
;; Clojure (.split "a b c" "\\s")
destructive initialisation/setting
// Java java.util.Map<String, Integer> m = new java.util.HashMap<>(); m.put("a", 1); m.put("b", 2); m.put("c", 3); return m;
;; Clojure (doto (java.util.HashMap.) (.put "a" 1) (.put "b" 2) (.put "c" 3))
method chaining
// Java new StringBuilder() .append("a") .append("b") .append("c") .toString()
;; Clojure (.. (StringBuilder.) (append "a") (append "b") (append "c") toString) ;; or (-> (StringBuilder.) (.append "a") (.append "b") (.append "c") .toString)
Interoperating with Java collection API
Java collection → Clojure function
user=> (def xs (doto (java.util.ArrayList.) #_=> (.add 1) #_=> (.add 2) #_=> (.add 3))) #'user/xs
user=> (class xs) java.util.ArrayList
user=> xs [1 2 3]
user=> (map inc xs) (2 3 4)
Clojure collection → Java method
user=> (def xs [1 2 3 4 5]) #'user/xs
user=> (class xs) clojure.lang.PersistentVector
user=> (instance? java.util.List xs) true
user=> (.subList xs 1 4) [2 3 4]
cf. usage example of Google Sheets API (Java)
// Java public Integer duplicateWorksheet(Sheets sheets, String spreadsheetId, Integer worksheetId, String worksheetName) List<Request> reqs = Arrays.asList( new Request().setDuplicateSheet( new DuplicateSheetRequest().setSourceSheetId(worksheetId) .setNewSheetName(worksheetName) .setInsertSheetIndex(1) ) ); return executeUpdate(sheets, spreadsheetId, worksheetId, reqs) .getReplies() .get(0) .getDuplicateSheet() .getProperties() .getSheetId(); }
;; Clojure (defn duplicate-worksheet [sheets spreadsheet-id worksheet-id worksheet-name] (let [reqs [(-> (Request.) (.setDuplicateSheet (-> (DuplicateSheetRequest.) (.setSourceSheetId worksheet-id) (.setNewSheetName worksheet-name) (.setInsertSheetIndex (int 1)))))]] (-> (execute-update sheets spreadsheet-id worksheet-id reqs) .getReplies first .getDuplicateSheet .getProperties .getSheetId)))
Furthermore,
core.async
transducers
clojure.spec
ClojureScript
etc.
If you use Clojure,with the power of FP, Lisp and Java
you can program more simply, more freely!!
Vive les S-expressions !
Long live S-expressions!
Further Reading
: Clojure o�cial site
: Clojure build tool
: Clojure build tool
: Clojure online REPL
: ClojureScript online REPL
Chapter 7: Clojure
Clojure
Leiningen
Boot
Try Clojure
Replumb REPL
Seven Languages in Seven Weeks
Programming Clojure (2nd edition)