Upgrade to Pro — share decks privately, control downloads, hide ads and more …

From Java To Clojure

From Java To Clojure

JavaからClojureへ
JavaプログラマこそClojureを始めよう!
cf. English version: https://speakerdeck.com/lagenorhynque/from-java-to-clojure-english-version

Kent OHASHI

January 28, 2017
Tweet

More Decks by Kent OHASHI

Other Decks in Programming

Transcript

  1. 自己紹介 lagénorhynque /laʒenɔʁɛ̃k/ (defprofile lagénorhynque :name "Kent OHASHI" :account @lagenorhynque

    :company 株式会社オプト :languages [Clojure Haskell Python Scala English français Deutsch русский] :interests [ プログラミング 語学 数学])
  2. 独断と偏見によるJVM 言語比較 factor Java Groovy Scala Kotlin Clojure FP support

    × △ ◯ △ ◯ simplicity × ◯ △ ◯ ◎ exibility × ◯ ◯ ◯ ◎
  3. 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
  4. イミュータブルな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}
  5. 高階関数(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
  6. ちなみに、 #( ) は #(* % %) ↓↓↓ (fn [x]

    (* x x)) に相当するリーダマクロ
  7. ちなみに、 ->> は (->> a (f x) (g y) (h

    z)) ↓↓↓ (h z (g y (f x a))) に展開されるマクロ(threading macro の一種)
  8. 遅延シーケンス 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)
  9. S 式( ) S-expressions (f a b c ...) f:

    関数, マクロ, 特殊形式 a, b, c, ...: 引数 cf. Java f(a, b, c, ...)
  10. 関数/ メソッドの定義も // Java public void greet(String name) { System.out.println("Bonjour,

    " + name + " !"); } S 式 ;; Clojure (defn greet [name] (println (str "Bonjour, " name " !")))
  11. 名前空間/ パッケージの宣言もインポートも // 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)))
  12. 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)
  13. 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
  14. 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)
  15. ちなみに、 関数定義の defn は user=> (macroexpand #_=> '(defn greet [name]

    #_=> (println (str "Bonjour, " name " !")))) (def greet (clojure.core/fn ([name] (println (str "Bonjour, " name " !"))))) 特殊形式 def, fn を利用したマクロ
  16. 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!
  17. Java メソッドの呼び出し static メソッド // Java Integer.parseInt("123") ;; Clojure (Integer/parseInt

    "123") インスタンスメソッド // Java "a b c".split("\\s") ;; Clojure (.split "a b c" "\\s")
  18. 破壊的な初期化/ 設定 // 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))
  19. メソッドチェーン // 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)
  20. 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)
  21. 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]
  22. 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)))
  23. Further Reading : Clojure 公式 : Clojure のビルドツール : Clojure

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