Last active
August 29, 2015 13:57
-
-
Save fanannan/9579301 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Schemaの紹介 | |
Schemaとは | |
・Prismatic社製の型チェックライブラリ | |
・最新版は “0.2.1” | |
https://github.com/prismatic/schema | |
型チェック?? | |
・なんでClojureで型チェック? | |
・でも、あえて型チェックしたいなら? | |
普通に関数の本体でチェックする | |
(defn sample [x] | |
(if (number? x) | |
(+ x 1) | |
(throw (Exception. “error!”)))) | |
preでチェックする | |
(defn sample [x] | |
{:pre [(number? x)] | |
(+ x 1)) | |
core.typedでチェックする | |
(require '[clojure.core.typed :as ty]) | |
(ty/ann sample [Number]) | |
(defn sample [x] | |
(+ x 1)) | |
Schemaを使うと? | |
(require '[schema.macro :as sm]) | |
(sm/defn sample [x :- Number] | |
(+ x 1)) | |
なんでSchema? | |
・ コードが分かりやすくなる | |
・ 必要なところで使える | |
・ マップのチェックができる | |
・ 型の定義が柔軟かつ簡単明快 | |
・ 複雑な構造もチェックできる | |
・ 速くなる | |
副作用のない純粋な関数の例 | |
(defn update-share-counts [share-counts updates] | |
(reduce | |
(fn [result [user-id share-type delta]] | |
(update-in result | |
[share-type (str user-id)] | |
(fnil + 0) | |
delta))) | |
share-counts | |
updates)) | |
じゃあ | |
(defn update-share-counts | |
"Increment share-counts according to the share actions in updates: | |
share-counts: map from user-id to map of share-type | |
(must be one of :twitter, :facebook, or :email) to | |
count of number of shares (a long) | |
updates: sequence of triples [user-id share-type delta], where delta is | |
amount to increment share-type by | |
returns updated share-counts reflecting shares in updates" | |
[share-counts updates] | |
こうなる | |
(sm/defn update-share-counts :- UserShareCounts | |
[share-counts :- UserShareCounts | |
updates :- [UserShareUpdate]] | |
(reduce | |
(fn [result [user-id share-type delta]] | |
(update-in result | |
[share-type (str user-id)] | |
(fnil + 0) | |
delta)) | |
share-counts | |
updates)) | |
コードが分かりやすくなる | |
・ 関数の引数や返値の型がひと目で分かる。 | |
・ Prismatic: ”ドキュメント文字列より関数の定義の方が速く変化する” | |
(sm/defn make-train-dataset :- DataSet | |
"モデル訓練用データセットの作成" | |
[r :- Resource, | |
cfg :- Config, | |
cat :- Category, | |
job-type :- Keyword, | |
job-desc :- Job, | |
model-info :- Model-info] | |
ちょっと覗いて見ると | |
(sm/defn sample :- String | |
"数値を文字列に変換" | |
[x :- Long] | |
(str x)) | |
(clojure.pprint/pprint (meta #'sample)) | |
{:arglists ([x]), | |
:ns #<Namespace schema-test.core>, | |
:name sample, | |
:column 1, | |
:raw-arglists ([x :- Long]), | |
:doc "Inputs: [x :- Long]\n Returns: String\n\n 数値を文字列に変換", | |
:schema {:output-schema java.lang.String, | |
:input-schemas ([{:schema java.lang.Long, :optional? false, :name x}])}, | |
:line 1, | |
:file "/tmp/form-init1376864852441125993.clj", | |
:tag java.lang.String} | |
必要なところで使える | |
・ 関数や無名関数の引数、返値や、関数本体の中での型チェックなどが可能 | |
- Schema版のdefn, fn, letfn, defrecord等 | |
- validate, checkなどの型判定関数 | |
(sm/defn sample :- Number | |
[x :- Number] | |
(s/validate Number (+ x 1))) | |
マップの構造のチェックができる | |
・マップのキーや要素についてのチェックができる | |
{:name String, :age Integer} | |
{:name String, (s/optional-key :age) Integer} | |
”型”の定義が柔軟かつ簡単明快 | |
・Javaのクラスがそのまま使える(instance?と同様) | |
・複合的な”型”が定義できる | |
(s/either java.lang.Byte Boolean) | |
(s/both Number (s/pred pos?)) | |
複雑な構造もチェックできる | |
・入れ子や再帰的な”型”の定義も可能 | |
(def Record {:id Number, :name String}) | |
(def Structure {:tag Keyword [Record])}) | |
速くなる | |
・型チェックをするモードと、しないモードの使い分けができる。 | |
・タイプヒントとして機能する。 | |
Schemaの使い方 | |
project.clj | |
(defproject schema-test "0.1.0-SNAPSHOT" | |
:dependencies | |
[[org.clojure/clojure "1.5.1"] | |
; Schema | |
[prismatic/schema "0.2.1"] | |
:main schema-test.core) | |
オーバーヘッドは? | |
(require '[clojure.core.typed :as ty]) | |
(require '[criterium.core :as cr]) | |
(defn no-check [x](+ x 1)) | |
(defn pre-check [x]{:pre [(number? x)]}(+ x 1)) | |
(defn body-check [x](when (number? x)(+ x 1))) | |
(defn hint [^Number x](+ x 1)) | |
(defn ^Number hint2 [^Number x](+ x 1)) | |
(ty/ann typed-check [Number -> Number]) | |
(defn typed-check [x](+ x 1)) | |
(sm/defn schema-no-check [x](+ x 1)) | |
(sm/defn schema-arg-check [x :- Number](+ x 1)) | |
(sm/defn schema-arg-check2 :- Number [x :- Number](+ x 1)) | |
(sm/defn ^:always-validate schema-always-arg-check [x :- Number](+ x 1)) | |
ベンチマーク結果 | |
Prismatic: “オーバーヘッドは5%くらい” | |
メリットまとめ | |
・コードの可読性が増し、メンテしやすい。 | |
・ドキュメント文字列に気を使うことが減る。 | |
・型チェックは必要なとき、必要なところだけ有効にすれば良いので、速度のハンデは事実上ない。むしろ、タイプヒントの効果も期待できる(かも)。 | |
・とにかく、使いやすい | |
でもまだα版です・・・・。 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment