>100 Views
February 19, 17
スライド概要
Let's start Clojure, Java programmers!
cf. 日本語版: https://www.docswell.com/s/lagenorhynque/Z24239-from-java-to-clojure
「楽しく楽にcoolにsmartに」を理想とするprogrammer/philosopher/liberalist/realist。 好きな言語はClojure, Haskell, Python, English, français, русский。 読書、プログラミング、語学、法学、数学が大好き! イルカと海も大好き🐬
From Java To Clojure - Adieu Java -
Self-introduction ̃ / lagénorhynque /laʒenɔʁɛk (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 comparison from my own point of view factor Java FP support × simplicity × exibility × Groovy △ ◯ ◯ Scala ◯ △ ◯ Kotlin △ ◯ ◯ Clojure ◯ ◎ ◎
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, where the s/j has the zh sound as in azure, pleasure etc. The name was chosen to be unique. I wanted to involve c (c#), l (lisp) and j (java). Once I came up with Clojure, given the pun on closure, 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 /ˈkloʊʒɚ/ meaning 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 form a, 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 macros powerful 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 les executable 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, Strin
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: Clojure o cial site Leiningen: Clojure build tool Boot: Clojure build tool Try Clojure: Clojure online REPL Replumb REPL: ClojureScript online REPL Seven Languages in Seven Weeks Chapter 7: Clojure Programming Clojure (2nd edition)