キメるClojure
kawasima
Clojureとは何か
どういう特長があるのか?
Clojureならではなこと…
文法 → Lisp方言
イミュータブルなデータ構造 → HaskellやScalaにもある
遅延評価 → その他多くの関数型言語と同じ
CSP(core.async) → golangと同じ
Future/Promise → JavaのFutureそのもの
Almost nothing in Clojure is new
(Clojure Appliedより)
枯れた技術/概念を
バランスよく配合した言語
●
Javaとの距離感
型をWrapせず、そのまま使う。
性能が気になるのであれば、Javaで書けばいいさ。
●
Lispとの距離感
●
括弧の種類を増やす禁断の一手。だが程よく読みやすくなる。
Make reasoned choices
(Clojure Appliedより)
ちょっと準備
Syntax
Clojure Ruby
String "Clojure" "Ruby"
Keyword :clojure :ruby
(Symbol)
Numeric 123 (long)
123.0 (double)
22/7 (Ratio)
123 (Integer)
123.0 (Float)
22r/7 (Rational)
List (1 2 3) -
Vector [1 2 3] [1,2,3]
(Array)
Set #{1 2 3} Set[1, 2, 3]
Map {:a 1 :b "a"} {a: 1, b: "a"}
(Hash)
Clojure's S式の読み方
http://www.pixelmonkey.org/wordpress/wp-content/uploads/2014/11/clojure_syntax.png
はい、もう読めますねー
キメてみよう
Clojureはキメると気持ちイイ
キマりやすいfeatureをご紹介していきます
Lazy Sequence
Lispがキマりやすい 、 Fibonacci sequence
(def fib
(lazy-cat [0 1]
(map + fib (rest fib))))
再帰と遅延シーケンスの絶妙のハーモニー
こういうロジック
fib 0,1,...
(rest fib) 1,...
fib 0,1,1..
(rest fib) 1,1,..
fib 0,1,1,2...
(rest fib) 1,1,2,...
fib 0,1,1,2,3...
(rest fib) 1,1,2,3,..
fib 0,1,1,2,3,5...
(rest fib) 1,1,2,3,5..
get-in
業務アプリ頻出の深いデータ構造を一発でアクセス
(get-in ctx [:request :params
:address 2 :prefecture])
=> 東京都
{:request
{:params
{:address
[{:prefecture "長崎県"}
{:prefecture "大阪府"}
{:prefecture "東京都"}]}}}
(update-in ctx [:request :params
:address 2 :prefecture]
clojure.string/replace
#"府$" "都")
{:request
{:params
{:address
[{:prefecture "長崎県"}
{:prefecture "大阪都"}
{:prefecture "東京都"}]}}}
update-in
業務アプリ頻出の深いデータ構造を一発で更新
そんなの他の言語でもできるよ
=>ctx[:request][:params][:address][2][:prefecture]
=>ctx[:request][:params][:address][2][:prefecture]
NoMethodError: undefined method `[]' for nil:NilClass
from (irb):4
from /usr/bin/irb:11:in `<main>'
user => (get-in ctx [:request :params :address 2
:prefecture])
nil
ruby
たどる途中でnilになっても、エラーにならない!
Clojure
Multimethod
データの型や値、属性によって、動的に呼ぶ関数を切り
替えるしくみ
HTMLやXMLのパーサ書くときにも、タグや属性でキレ
イに処理を分けられるので、キメキメに書ける。
Excelのパース
Threading Macro
関数の呼び出し順を、他の言語と同じようにしてくれる。
これだけでも十分、気持ちいいが…
(.toUpperCase (str (first [:cat :dog :fish])))
(-> [:cat :dog :fish] first str .toUpperCase)
↑が↓のように書ける
"some" threading macro
Optionalなんかなくても、やりたいことって、
nilが帰ってきたらそこで処理を抜けてくれることやろ?
promise/deliver
Seleniumでパスワードはスクリプトに含めたくない。
ダイアログ開いてパスワード入力されたら、スクリプトを継続
Destructing
String kanaSei = request.getParamter("KANA_SEI");
String kanaMei = request.getParamter("KANA_MEI");
String kanjiSei = request.getParamter("KANJI_SEI");
String kanjiMei = request.getParamter("KANJI_MEI");
String mailUser = request.getParameter("MAIL_USER");
String mailDomain = request.getParameter("MAIL_DOMAIN");
(let [{{:keys [kana-sei kana-mei kanji-sei kanji-mei
mail-user mail-domain]} :params} request]
(println "Name=" kanji-sei kanji-mei))
こんなコード、よく見かけるけど…
そんな代入派も、最小の手数で変数束縛できる
複雑な構造も一発で、束縛できる
デフォルト値もセットできる
はい、キマってきましたね
Clojureのライブラリも
キマっている
Ring
(-> handler
(wrap wrap-anti-forgery (get-in config [:security :anti-forgery] false))
(wrap wrap-flash (get-in config [:session :flash] false))
(wrap wrap-session (:session config false))
(wrap wrap-keyword-params (get-in config [:params :keywordize] false))
(wrap wrap-nested-params (get-in config [:params :nested] false))
(wrap wrap-multipart-params (get-in config [:params :multipart] false))
(wrap wrap-params (get-in config [:params :urlencoded] false))
(wrap wrap-cookies (get-in config [:cookies] false))
(wrap wrap-absolute-redirects (get-in config [:responses :absolute-redirects] false))
(wrap wrap-resource (get-in config [:static :resources] false))
(wrap wrap-file (get-in config [:static :files] false))
(wrap wrap-content-type (get-in config [:responses :content-types] false))
(wrap wrap-default-charset (get-in config [:responses :default-charset] false))
(wrap wrap-not-modified (get-in config [:responses :not-modified-responses]
false))
(wrap wrap-x-headers (:security config))
(wrap wrap-hsts (get-in config [:security :hsts] false))
(wrap wrap-ssl-redirect (get-in config [:security :ssl-redirect] false))
(wrap wrap-forwarded-scheme (boolean (:proxy config)))
(wrap wrap-forwarded-remote-addr (boolean (:proxy config)))))
統一されたMiddlewareインタフェース
Compojure
2000行のスモールフレームワークSinatraに対し、
Compojureは500行以下
(ringもweavejester先生が設計してることが大きい)
(defroutes api-routes
(ANY "/token" [] token-resource)
(ANY "/boards" [] boards-resource)
(ANY "/board/:board-name" [board-name]
(board-resource board-name))
(ANY "/board/:board-name/threads" [board-name]
(threads-resource board-name))
(ANY "/thread/:thread-id" [thread-id]
(thread-resource (Long/parseLong thread-id)))
(ANY "/thread/:thread-id/comments" [thread-id]
(comments-resource (Long/parseLong thread-id) 1 nil)))
宣言的にルーティングを書ける。
core.async
goのchannlと同じものを簡単に使える
http://www.slideshare.net/kawasima/shibuya-jvm-1clojure
core.asyncのデザインの素晴らしさは拙作スライドをご覧ください
Liberator
REST APIを宣言的に書ける
HTTPステータスコードマニアには
たまらない
buddy
認証・認可のしくみも美しい
API用認証を付け足すのもシンプル
デファクトスタンダードのライブラリが、
ことごとく
➔
洗練されたデザイン
➔
小さくて読みやすい
➔
比較的、仕様が安定している
まとめ
Clojureをキメると気持ちイイ
質の高いライブラリ群はさらに気持ちイイ

キメるClojure