Slide 1

Slide 1 text

Java からClojure へ - Adieu Java -

Slide 2

Slide 2 text

自己紹介 lagénorhynque /laʒenɔʁɛ̃k/ (defprofile lagénorhynque :name "Kent OHASHI" :account @lagenorhynque :company 株式会社オプト :languages [Clojure Haskell Python Scala English français Deutsch русский] :interests [ プログラミング 語学 数学])

Slide 3

Slide 3 text

Lisp × Java

Slide 4

Slide 4 text

言語としてのJava

Slide 5

Slide 5 text

言語としてのJava の問題点 関数型プログラミング(FP) サポートの不足 もっとFP したい! (OOP 要素も静的型付けも必須ではない) 冗長なシンタックス もっとシンプルに書きたい! 柔軟性/ 拡張性の不足 もっと自由に書きたい!

Slide 6

Slide 6 text

独断と偏見によるJVM 言語比較 factor Java Groovy Scala Kotlin Clojure FP support × △ ◯ △ ◯ simplicity × ◯ △ ◯ ◎ exibility × ◯ ◯ ◯ ◎

Slide 7

Slide 7 text

Clojure を使えば、 言語としての Java とはお別れできる!! Adieu, Java ! Java ともこれで本当にお別れだね(;_;)/~~~

Slide 8

Slide 8 text

What is Clojure?

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

Clojure /ˈkloʊʒɚ/ ※ NOT /ˈkloʊd͡ʒɚ/ element meaning /ˈkloʊʒɚ/ クロージャ(closure), 関数型プログラミング C C#(.NET) as a platform, .NET 言語 l Lisp 方言 j Java as a platform, JVM 言語

Slide 11

Slide 11 text

1. FP 言語としてのClojure 2. Lisp 方言としてのClojure 3. JVM 言語としてのClojure

Slide 12

Slide 12 text

FP 言語としてのClojure

Slide 13

Slide 13 text

イミュータブルな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}

Slide 14

Slide 14 text

高階関数(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

Slide 15

Slide 15 text

ちなみに、 #( ) は #(* % %) ↓↓↓ (fn [x] (* x x)) に相当するリーダマクロ

Slide 16

Slide 16 text

ちなみに、 ->> は (->> a (f x) (g y) (h z)) ↓↓↓ (h z (g y (f x a))) に展開されるマクロ(threading macro の一種)

Slide 17

Slide 17 text

遅延シーケンス 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)

Slide 18

Slide 18 text

Lisp 方言としてのClojure

Slide 19

Slide 19 text

S 式( ) S-expressions (f a b c ...) f: 関数, マクロ, 特殊形式 a, b, c, ...: 引数 cf. Java f(a, b, c, ...)

Slide 20

Slide 20 text

関数/ メソッドの定義も // Java public void greet(String name) { System.out.println("Bonjour, " + name + " !"); } S 式 ;; Clojure (defn greet [name] (println (str "Bonjour, " name " !")))

Slide 21

Slide 21 text

名前空間/ パッケージの宣言もインポートも // 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)))

Slide 22

Slide 22 text

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)

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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)

Slide 25

Slide 25 text

ちなみに、 関数定義の defn は user=> (macroexpand #_=> '(defn greet [name] #_=> (println (str "Bonjour, " name " !")))) (def greet (clojure.core/fn ([name] (println (str "Bonjour, " name " !"))))) 特殊形式 def, fn を利用したマクロ

Slide 26

Slide 26 text

大量の括弧を扱うのがつらい? ⇒ Lisp 編集用プラグインがあれば非常に快適 The Animated Guide to Paredit Parinfer - simpler Lisp editing

Slide 27

Slide 27 text

JVM 言語としてのClojure

Slide 28

Slide 28 text

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!

Slide 29

Slide 29 text

Java メソッドの呼び出し static メソッド // Java Integer.parseInt("123") ;; Clojure (Integer/parseInt "123") インスタンスメソッド // Java "a b c".split("\\s") ;; Clojure (.split "a b c" "\\s")

Slide 30

Slide 30 text

破壊的な初期化/ 設定 // Java java.util.Map 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))

Slide 31

Slide 31 text

メソッドチェーン // 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)

Slide 32

Slide 32 text

Java コレクションAPI との連携 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)

Slide 33

Slide 33 text

Clojure のコレクション → Java のメソッド 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]

Slide 34

Slide 34 text

cf. Google Sheets API (Java 版) の利用例 // Java public Integer duplicateWorksheet(Sheets sheets, String spreadsheetId, Integer worksheetId, Strin List 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)))

Slide 35

Slide 35 text

ほかにも core.async transducers clojure.spec ClojureScript etc.

Slide 36

Slide 36 text

Clojure なら FP とLisp とJava の力を引き出して もっとシンプルに、もっと自由に、プログラミングできる!!

Slide 37

Slide 37 text

Vive les S-expressions ! S 式万歳!

Slide 38

Slide 38 text

Further Reading : Clojure 公式 : Clojure のビルドツール : Clojure のビルドツール : Clojure のオンラインREPL のひとつ : ClojureScript のオンラインREPL のひとつ 第7 章 Clojure Clojure Leiningen Boot Try Clojure Replumb REPL 『7 つの言語 7 つの世界』 『プログラミングClojure 第2 版』