196 Views
January 28, 17
スライド概要
JavaからClojureへ
JavaプログラマこそClojureを始めよう!
cf. English version: https://www.docswell.com/s/lagenorhynque/KRX24N-from-java-to-clojure-english-version
「楽しく楽にcoolにsmartに」を理想とするprogrammer/philosopher/liberalist/realist。 好きな言語はClojure, Haskell, Python, English, français, русский。 読書、プログラミング、語学、法学、数学が大好き! イルカと海も大好き🐬
からClojureへ Java - Adieu Java -
自己紹介 ̃ / lagénorhynque /laʒenɔʁɛk (defprofile lagénorhynque :name "Kent OHASHI" :account @lagenorhynque :company :languages [Clojure Haskell Python Scala English français Deutsch русский] :interests [ ]) 株式会社オプト プログラミング 語学 数学
Lisp × Java
言語としてのJava
言語としてのJavaの問題点 関数型プログラミング(FP)サポートの不足 もっとFPしたい! (OOP要素も静的型付けも必須ではない) 冗長なシンタックス もっとシンプルに書きたい! 柔軟性/拡張性の不足 もっと自由に書きたい!
独断と偏見によるJVM言語比較 factor Java FP support × simplicity × exibility × Groovy △ ◯ ◯ Scala ◯ △ ◯ Kotlin △ ◯ ◯ Clojure ◯ ◎ ◎
を使えば、 言語としての Java とはお別れできる!! Clojure Adieu, Java ! ともこれで本当にお別れだね(;_;)/~~~ Java
What is Clojure?
の名前の由来 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ʊʒɚ/ C l j meaning クロージャ(closure), 関数型プログラミング C#(.NET) as a platform, .NET言語 Lisp方言 Java as a platform, JVM言語
言語としてのClojure 2. Lisp方言としてのClojure 3. JVM言語としてのClojure 1. FP
言語としてのClojure FP
イミュータブルな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}
高階関数(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
ちなみに、 #( ) は #(* % %) ↓↓↓ (fn [x] (* x x)) に相当するリーダマクロ
ちなみに、 ->> は (->> a (f x) (g y) (h z)) ↓↓↓ (h z (g y (f x a))) に展開されるマクロ(threading macroの一種)
遅延シーケンス 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 Lisp
式 S (S-expressions) (f a b c ...) 関数 マクロ 特殊形式 引数 f: , , a, b, c, ...: cf. Java f(a, b, c, ...)
関数/メソッドの定義も
// Java
public void greet(String name) {
System.out.println("Bonjour, " + name + " !");
}
式
S
;; Clojure
(defn greet [name]
(println (str "Bonjour, " name " !")))
名前空間/パッケージの宣言もインポートも // Java package demo_app; import java.io.IOException; import java.util.ArrayList; import java.util.List; 式 S ;; 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 (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 強力なコンパイル時メタプログラミング機構 user=> (defmacro unless ; clojure.core/if-not #_=> ([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) マクロを再実装しただけ
ちなみに、 関数定義の defn は user=> (macroexpand #_=> '(defn greet [name] #_=> (println (str "Bonjour, " name " !")))) (def greet (clojure.core/fn ([name] (println (str "Bonjour, " name " !"))))) 特殊形式 def, fn を利用したマクロ
大量の括弧を扱うのがつらい? ⇒ Lisp編集用プラグインがあれば非常に快適 The Animated Guide to Paredit Parinfer - simpler Lisp editing
言語としてのClojure JVM
の ファイルにコンパイル Java class 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!
メソッドの呼び出し Java static メソッド // Java Integer.parseInt("123") ;; Clojure (Integer/parseInt "123") // Java "a b c".split("\\s") ;; Clojure (.split "a b c" "\\s") インスタンスメソッド
破壊的な初期化/設定 // 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))
メソッドチェーン // Java new StringBuilder() .append("a") .append("b") .append("c") .toString() ;; Clojure (.. (StringBuilder.) (append "a") (append "b") (append "c") toString) ;; (-> (StringBuilder.) (.append "a") (.append "b") (.append "c") .toString) または
コレクションAPIとの連携 Java Java のコレクション → Clojureの関数 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)
のコレクション → Javaのメソッド Clojure 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. 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)))
ほかにも core.async transducers clojure.spec ClojureScript etc.
Clojure なら と と の力を引き出して もっとシンプルに、もっと自由に、プログラミングできる!! FP Lisp Java
Vive les S-expressions ! 式万歳! S
Further Reading 公式 Leiningen: Clojureのビルドツール Boot: Clojureのビルドツール Try Clojure: ClojureのオンラインREPLのひとつ Replumb REPL: ClojureScriptのオンラインREPLのひとつ 『7つの言語 7つの世界』 第7章 Clojure 『プログラミングClojure 第2版』 Clojure: Clojure