SlideShare a Scribd company logo
1 of 47
Download to read offline
Everyday LifeEveryday Life
with clojure.specwith clojure.spec
lagénorhynquelagénorhynque
(defprofile lagénorhynque
:id @lagenorhynque
:reading "/laʒenɔʁɛ̃k/"
:aliases ["カマイルカ🐬 "]
:languages [Clojure Haskell English français]
:interests [programming language-learning law mathematics]
:commits ["github.com/lagenorhynque/duct.module.pedestal"
"github.com/lagenorhynque/duct.module.cambium"]
:contributes ["github.com/japan-clojurians/clojure-site-ja"])
1. Clojure
2. Clojure開発で困ること
3. clojure.spec
ClojureClojure
ClojureとはClojureとは
関数型⾔語
JVM⾔語
Lisp
動的型付き⾔語
が作った"simple"な⾔語Rich Hickey
簡単なプログラムの例簡単なプログラムの例dev> (defn hello [name]
(println (str "Hello, " name "!")))
#'dev/hello
dev> (hello "World")
Hello, World!
nil
dev> (hello "Clojure")
Hello, Clojure!
nil
Clojureでの開発のしかたClojureでの開発のしかた
コンパイルが通るようにひとまとまりのコードを
書き、コンパイルできたらたいてい期待通りに動
作する
優れた型システムを備えた静的型付き⾔語の
イメージ(?)
動くと思われるひとまとまりのコードを書き、動
かしてみて期待通りでなければ適宜デバッグする
典型的な動的型付き⾔語のイメージ(?)
REPLと繋がったエディタで⼩さな単位で動かし
ながらコードを書き、書き上がったひとまとまり
のコードは期待通りに動作する
ClojureなどLisp系⾔語での開発スタイル
いわゆる「REPL駆動開発」
多くのLispではREPL周りのツールが⾼
度に発達している
REPLと連携しながらの開発を前提に⾔
語が設計されているとさえ考えられる
Clojure開発で困ることClojure開発で困ること
例えば、こんな関数を定義する例えば、こんな関数を定義する
様々な暗黙の前提がある(使う側は知る由もない)
(defn find-artists [ds {:keys [name ids sort-order]}]
(jdbc/execute!
ds
(cond-> (sql/build
:select :*
:from :artist)
name (merge-where [:like :name (str % name %)])
(seq ids) (merge-where [:in :id ids])
(seq sort-order) (#(apply merge-order-by % sort-order))
(empty? sort-order) (merge-order-by [:id :asc])
true sql/format)))
使ってみると使ってみると
正しい使い⽅を知っていれば期待通りに動作する
example> (find-artists (ds) {})
[#:artist{:id 1, :type 1, :name "Aqours"}
#:artist{:id 2, :type 1, :name "CYaRon!"}
#:artist{:id 3, :type 1, :name "AZALEA"}
#:artist{:id 4, :type 1, :name "Guilty Kiss"}
#:artist{:id 5, :type 1, :name "Saint Snow"}
#:artist{:id 6, :type 1, :name "Saint Aqours Snow"}]
example> (find-artists (ds) {:name "Aq"})
[#:artist{:id 1, :type 1, :name "Aqours"}
#:artist{:id 6, :type 1, :name "Saint Aqours Snow"}]
example> (find-artists (ds) {:ids [2]})
[#:artist{:id 2, :type 1, :name "CYaRon!"}]
しかし……しかし……
唐突に、LongからISeqを作る⽅法が分からない
と⾔われたり
Clojurianにはお馴染み😅
example> (find-artists (ds) {:ids 2})
Execution error (IllegalArgumentException) at everyday-life-with
-clojure-spec.example/find-artists (example.clj:40).
Don't know how to create ISeq from: java.lang.Long
PostgreSQLにアクセスするので⼊⼒の型が想定
と違うとPSQLExceptionが発⽣したり
example> (find-artists (ds) {:ids ["2"]})
Execution error (PSQLException) at org.postgresql.core.v3.QueryE
xecutorImpl/receiveErrorResponse (QueryExecutorImpl.java:2533).
ERROR: operator does not exist: bigint = character varying
Hint: No operator matches the given name and argument types. Y
ou might need to add explicit type casts.
Position: 32
明らかにDB接続情報でないものを与えると
SQLExceptionが発⽣したり
example> (find-artists "foo" {})
Execution error (SQLException) at java.sql.DriverManager/getConn
ection (DriverManager.java:702).
No suitable driver found for foo
エラーメッセージが分かりづらい
エラーメッセージの不親切さに定評がある😇
fail-fastでない
"garbage in, garbage out" 🗑
⼊出⼒として想定しているものが分からない
ドキュメントで冗⻑かつ不明確に説明したい
わけでもない
関数型⾔語なので不可解な副作⽤に悩まされ
ることは少ないとはいえ……
従来のアプローチ従来のアプローチ
スキーマ記述とバリデーションのためのサー
ドパーティライブラリ
(→ )
gradual/optional typingのための準標準ライ
ブラリ
schema
core.typed Typed Clojure
静的型付けのClojureがほしい?静的型付けのClojureがほしい?
clojure.specclojure.spec
コントラクト(契約)システムコントラクト(契約)システム
e.g. Racketのcontract system
> (define/contract (maybe-invert i b)
(-> integer? boolean? integer?)
(if b (- i) i))
> (maybe-invert 1 #t)
-1
> (maybe-invert #f 1)
maybe-invert: contract violation
expected: integer?
given: #f
in: the 1st argument of
(-> integer? boolean? integer?)
contract from: (function maybe-invert)
blaming: top-level
(assuming the contract is correct)
at: eval:2.0
The Racket Reference > 8.2 Function Contracts
標準ライブラリclojure.spec標準ライブラリclojure.spec
cf.
述語(predicate)による仕様記述システム
NOT 型システム
spec.alpha
spec-alpha2 (alpha.spec)
core.specs.alpha
clojure.specを導⼊するclojure.specを導⼊するexample> (require '[clojure.spec.alpha :as s])
nil
この関数に"spec"を付けたいこの関数に"spec"を付けたい(defn find-artists [ds {:keys [name ids sort-order]}]
(jdbc/execute!
ds
(cond-> (sql/build
:select :*
:from :artist)
name (merge-where [:like :name (str % name %)])
(seq ids) (merge-where [:in :id ids])
(seq sort-order) (#(apply merge-order-by % sort-order))
(empty? sort-order) (merge-order-by [:id :asc])
true sql/format)))
仕様を⾃然⾔語で表現してみると仕様を⾃然⾔語で表現してみると
引数
ds: javax.sql.DataSource オブジェクト
{:keys [name ids sort-order]}: 以下
のキーを含むかもしれない検索条件マップ
:name: ⽂字列
:ids: ⾃然数の空でないシーケンス
:sort-order: ソートキーのキーワー
ドと昇順/降順の:asc または:desc の
ペアの空でなく第1要素についてユニー
クなシーケンス
戻り値
アーティストマップのシーケンス
アーティストマップ: 以下のキーを必ず
含むマップ
:id: ⾃然数
:type: 1 (グループ) または2 (ソロ)
:name: ⽂字列
s/fdefs/fdef マクロで記述するとマクロで記述すると
s/fdef は関数に対するspecを定義する
;;; 関数 find-artists に対するspec定義のイメージ
;;; ,,, 部分を埋めたい
(s/fdef find-artists
:args (s/cat :ds ,,, ; 第1引数
:condition ,,,) ; 第2引数
:ret ,,,) ; 戻り値
アーティストマップをspecとして記述してみる
s/def はspec(= 述語)に名前を付ける
s/valid? はspecを満たすかどうか判定する
example> (s/def :artist/id nat-int?)
:artist/id
example> (s/def :artist/type #{1 2})
:artist/type
example> (s/def :artist/name string?)
:artist/name
example> (s/def ::artist (s/keys :req [:artist/id
:artist/type
:artist/name]))
:everyday-life-with-clojure-spec.example/artist
example> (s/valid? ::artist #:artist{:id 1
:type 2
:name "You Watanabe"})
true
戻り値のspec定義が定まる
;;; 関数 find-artists に対するspec定義のイメージ
;;; ,,, 部分を埋めたい
(s/fdef find-artists
:args (s/cat :ds ,,, ; 第1引数
:condition ,,,) ; 第2引数
:ret (s/coll-of ::artist)) ; 戻り値
DataSource であることをspecとして記述してみる
example> (import '(javax.sql DataSource))
javax.sql.DataSource
example> (s/valid? #(instance? DataSource %) (ds))
true
example> (s/valid? #(instance? DataSource %) "foo")
false
第1引数のspecが定まる
;;; 関数 find-artists に対するspec定義のイメージ
;;; ,,, 部分を埋めたい
(s/fdef find-artists
:args (s/cat :ds #(instance? DataSource %) ; 第1引数
:condition ,,,) ; 第2引数
:ret (s/coll-of ::artist)) ; 戻り値
:ids キーの値をspecとして記述してみる
example> (s/def ::ids (s/coll-of :artist/id
:min-count 1))
:everyday-life-with-clojure-spec.example/ids
example> (s/valid? ::ids [])
false
example> (s/valid? ::ids [2])
true
example> (s/valid? ::ids [2 4])
true
example> (s/valid? ::ids [2 2])
true
:sort-order キーの値をspecとして記述してみる
example> (s/def ::sort-order
(s/and (s/coll-of (s/tuple #{:id :type :name}
#{:asc :desc})
:min-count 1)
#(apply distinct? (map first %))))
:everyday-life-with-clojure-spec.example/sort-order
example> (s/valid? ::sort-order [])
false
example> (s/valid? ::sort-order [[:name :asc] [:id :desc]])
true
example> (s/valid? ::sort-order [[:name :misc] [:id :desc]])
false
example> (s/valid? ::sort-order [[:name :asc] [:name :desc]])
false
第2引数のspecが定まり、関数のspecが仕上がる
ex> (s/fdef find-artists
:args (s/cat :ds #(instance? DataSource %)
:condition (s/keys :opt-un [:artist/name
::ids
::sort-order]))
:ret (s/coll-of ::artist))
everyday-life-with-clojure-spec.example/find-artists
関数のspecを実装に組み込む関数のspecを実装に組み込む
(instrumentation)(instrumentation)
stest/instrument は関数のspecの引数に対す
るチェックを関数の実装に組み込む
実際の開発環境では開発/テスト時に⾃動的
に組み込まれるように設定することが多い
example> (require '[clojure.spec.test.alpha :as stest])
nil
example> (stest/instrument `find-artists)
[everyday-life-with-clojure-spec.example/find-artists]
改めて使ってみると改めて使ってみると
想定通りの⼊⼒に対して変わらず動作する
example> (find-artists (ds) {})
[#:artist{:id 1, :type 1, :name "Aqours"}
#:artist{:id 2, :type 1, :name "CYaRon!"}
#:artist{:id 3, :type 1, :name "AZALEA"}
#:artist{:id 4, :type 1, :name "Guilty Kiss"}
#:artist{:id 5, :type 1, :name "Saint Snow"}
#:artist{:id 6, :type 1, :name "Saint Aqours Snow"}]
example> (find-artists (ds) {:name "Aq"})
[#:artist{:id 1, :type 1, :name "Aqours"}
#:artist{:id 6, :type 1, :name "Saint Aqours Snow"}]
example> (find-artists (ds) {:ids [2]})
[#:artist{:id 2, :type 1, :name "CYaRon!"}]
そして……そして……
specに違反すると直ちにエラーになってくれる
⼊⼒のどの値がどのspecに違反しているか教え
てくれる
example> (find-artists (ds) {:ids 2})
Execution error - invalid arguments to everyday-life-with-clojur
e-spec.example/find-artists at (form-init8369102478102661347.clj
:747).
2 - failed: coll? at: [:condition :ids] spec: :everyday-life-wit
h-clojure-spec.example/ids
example> (find-artists (ds) {:ids ["2"]})
Execution error - invalid arguments to everyday-life-with-clojur
e-spec.example/find-artists at (form-init8369102478102661347.clj
:753).
"2" - failed: nat-int? at: [:condition :ids] spec: :artist/id
example> (find-artists "foo" {})
Execution error - invalid arguments to everyday-life-with-clojur
e-spec.example/find-artists at (form-init8369102478102661347.clj
:750).
"foo" - failed: (instance? javax.sql.DataSource %) at: [:ds]
その他の主な活⽤⽅法その他の主な活⽤⽅法
specによるドキュメンテーション
clojure.repl/doc の出⼒にも反映される
specによるバリデーション
specからサンプルデータの⾃動⽣成
specによるproperty-based testing
cf. test.check
関連サードパーティライブラリ関連サードパーティライブラリ
: specのinstrument 時のチェックを
強化する
: specのエラーメッセージを⾒やすく表
⽰する
: 標準ライブラリ関数/マクロに対す
るspecを独⾃に提供する
: specを静的解析に利⽤する試み
Orchestra
Expound
speculative
spectrum
clojure.specの登場でclojure.specの登場で
Clojurianの⽇常は⼀変しているClojurianの⽇常は⼀変している
イマドキのClojure開発をぜひ体験しよう!
Further ReadingFurther Reading
ClojureClojure
Clojure/ClojureScript関連リンク集
標準ライブラリ
clojure.specclojure.spec
clojure.spec - Rationale and Overview
⽇本語版
spec Guide
clojure.spec関連ライブラリclojure.spec関連ライブラリ
cf.
Orchestra
Expound
Pinpointer
speculative
spectrum
コントラクトシステム(Racket)コントラクトシステム(Racket)
The Racket Guide > 7 Contracts
The Racket Reference > 8 Contracts
サンプルコードサンプルコード
lagenorhynque/everyday-life-with-clojure-spec
lagenorhynque/spec-examples

More Related Content

What's hot

RLSを用いたマルチテナント実装 for Django
RLSを用いたマルチテナント実装 for DjangoRLSを用いたマルチテナント実装 for Django
RLSを用いたマルチテナント実装 for DjangoTakayuki Shimizukawa
 
WebSocketのキホン
WebSocketのキホンWebSocketのキホン
WebSocketのキホンYou_Kinjoh
 
Javaのログ出力: 道具と考え方
Javaのログ出力: 道具と考え方Javaのログ出力: 道具と考え方
Javaのログ出力: 道具と考え方Taku Miyakawa
 
Goの時刻に関するテスト
Goの時刻に関するテストGoの時刻に関するテスト
Goの時刻に関するテストKentaro Kawano
 
シェル芸初心者によるシェル芸入門
シェル芸初心者によるシェル芸入門シェル芸初心者によるシェル芸入門
シェル芸初心者によるシェル芸入門icchy
 
ドメイン駆動設計 失敗したことと成功したこと
ドメイン駆動設計 失敗したことと成功したことドメイン駆動設計 失敗したことと成功したこと
ドメイン駆動設計 失敗したことと成功したことBIGLOBE Inc.
 
C# 8.0 非同期ストリーム
C# 8.0 非同期ストリームC# 8.0 非同期ストリーム
C# 8.0 非同期ストリーム信之 岩永
 
PostgreSQLクエリ実行の基礎知識 ~Explainを読み解こう~
PostgreSQLクエリ実行の基礎知識 ~Explainを読み解こう~PostgreSQLクエリ実行の基礎知識 ~Explainを読み解こう~
PostgreSQLクエリ実行の基礎知識 ~Explainを読み解こう~Miki Shimogai
 
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭するCEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭するYoshifumi Kawai
 
強いて言えば「集約どう実装するのかな、を考える」な話
強いて言えば「集約どう実装するのかな、を考える」な話強いて言えば「集約どう実装するのかな、を考える」な話
強いて言えば「集約どう実装するのかな、を考える」な話Yoshitaka Kawashima
 
「関心の分離」と「疎結合」 ソフトウェアアーキテクチャのひとかけら
「関心の分離」と「疎結合」   ソフトウェアアーキテクチャのひとかけら「関心の分離」と「疎結合」   ソフトウェアアーキテクチャのひとかけら
「関心の分離」と「疎結合」 ソフトウェアアーキテクチャのひとかけらAtsushi Nakamura
 
Spring Data RESTを利用したAPIの設計と、作り直しまでの道のり
Spring Data RESTを利用したAPIの設計と、作り直しまでの道のり Spring Data RESTを利用したAPIの設計と、作り直しまでの道のり
Spring Data RESTを利用したAPIの設計と、作り直しまでの道のり Rakuten Group, Inc.
 
例外設計における大罪
例外設計における大罪例外設計における大罪
例外設計における大罪Takuto Wada
 
Laravelでfacadeを使わない開発
Laravelでfacadeを使わない開発Laravelでfacadeを使わない開発
Laravelでfacadeを使わない開発Kenjiro Kubota
 
メタプログラミングって何だろう
メタプログラミングって何だろうメタプログラミングって何だろう
メタプログラミングって何だろうKota Mizushima
 
リッチなドメインモデル 名前探し
リッチなドメインモデル 名前探しリッチなドメインモデル 名前探し
リッチなドメインモデル 名前探し増田 亨
 
入門ClojureScript
入門ClojureScript入門ClojureScript
入門ClojureScriptsohta
 
ツール比較しながら語る O/RマッパーとDBマイグレーションの実際のところ
ツール比較しながら語る O/RマッパーとDBマイグレーションの実際のところツール比較しながら語る O/RマッパーとDBマイグレーションの実際のところ
ツール比較しながら語る O/RマッパーとDBマイグレーションの実際のところY Watanabe
 
Dockerセキュリティ: 今すぐ役に立つテクニックから,次世代技術まで
 Dockerセキュリティ: 今すぐ役に立つテクニックから,次世代技術まで Dockerセキュリティ: 今すぐ役に立つテクニックから,次世代技術まで
Dockerセキュリティ: 今すぐ役に立つテクニックから,次世代技術までAkihiro Suda
 
テストコードの DRY と DAMP
テストコードの DRY と DAMPテストコードの DRY と DAMP
テストコードの DRY と DAMPYusuke Kagata
 

What's hot (20)

RLSを用いたマルチテナント実装 for Django
RLSを用いたマルチテナント実装 for DjangoRLSを用いたマルチテナント実装 for Django
RLSを用いたマルチテナント実装 for Django
 
WebSocketのキホン
WebSocketのキホンWebSocketのキホン
WebSocketのキホン
 
Javaのログ出力: 道具と考え方
Javaのログ出力: 道具と考え方Javaのログ出力: 道具と考え方
Javaのログ出力: 道具と考え方
 
Goの時刻に関するテスト
Goの時刻に関するテストGoの時刻に関するテスト
Goの時刻に関するテスト
 
シェル芸初心者によるシェル芸入門
シェル芸初心者によるシェル芸入門シェル芸初心者によるシェル芸入門
シェル芸初心者によるシェル芸入門
 
ドメイン駆動設計 失敗したことと成功したこと
ドメイン駆動設計 失敗したことと成功したことドメイン駆動設計 失敗したことと成功したこと
ドメイン駆動設計 失敗したことと成功したこと
 
C# 8.0 非同期ストリーム
C# 8.0 非同期ストリームC# 8.0 非同期ストリーム
C# 8.0 非同期ストリーム
 
PostgreSQLクエリ実行の基礎知識 ~Explainを読み解こう~
PostgreSQLクエリ実行の基礎知識 ~Explainを読み解こう~PostgreSQLクエリ実行の基礎知識 ~Explainを読み解こう~
PostgreSQLクエリ実行の基礎知識 ~Explainを読み解こう~
 
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭するCEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
 
強いて言えば「集約どう実装するのかな、を考える」な話
強いて言えば「集約どう実装するのかな、を考える」な話強いて言えば「集約どう実装するのかな、を考える」な話
強いて言えば「集約どう実装するのかな、を考える」な話
 
「関心の分離」と「疎結合」 ソフトウェアアーキテクチャのひとかけら
「関心の分離」と「疎結合」   ソフトウェアアーキテクチャのひとかけら「関心の分離」と「疎結合」   ソフトウェアアーキテクチャのひとかけら
「関心の分離」と「疎結合」 ソフトウェアアーキテクチャのひとかけら
 
Spring Data RESTを利用したAPIの設計と、作り直しまでの道のり
Spring Data RESTを利用したAPIの設計と、作り直しまでの道のり Spring Data RESTを利用したAPIの設計と、作り直しまでの道のり
Spring Data RESTを利用したAPIの設計と、作り直しまでの道のり
 
例外設計における大罪
例外設計における大罪例外設計における大罪
例外設計における大罪
 
Laravelでfacadeを使わない開発
Laravelでfacadeを使わない開発Laravelでfacadeを使わない開発
Laravelでfacadeを使わない開発
 
メタプログラミングって何だろう
メタプログラミングって何だろうメタプログラミングって何だろう
メタプログラミングって何だろう
 
リッチなドメインモデル 名前探し
リッチなドメインモデル 名前探しリッチなドメインモデル 名前探し
リッチなドメインモデル 名前探し
 
入門ClojureScript
入門ClojureScript入門ClojureScript
入門ClojureScript
 
ツール比較しながら語る O/RマッパーとDBマイグレーションの実際のところ
ツール比較しながら語る O/RマッパーとDBマイグレーションの実際のところツール比較しながら語る O/RマッパーとDBマイグレーションの実際のところ
ツール比較しながら語る O/RマッパーとDBマイグレーションの実際のところ
 
Dockerセキュリティ: 今すぐ役に立つテクニックから,次世代技術まで
 Dockerセキュリティ: 今すぐ役に立つテクニックから,次世代技術まで Dockerセキュリティ: 今すぐ役に立つテクニックから,次世代技術まで
Dockerセキュリティ: 今すぐ役に立つテクニックから,次世代技術まで
 
テストコードの DRY と DAMP
テストコードの DRY と DAMPテストコードの DRY と DAMP
テストコードの DRY と DAMP
 

Similar to Everyday Life with clojure.spec

Scalamacrosについて
ScalamacrosについてScalamacrosについて
Scalamacrosについてdekosuke
 
Lisp batton - Common LISP
Lisp batton - Common LISPLisp batton - Common LISP
Lisp batton - Common LISPMasaomi CHIBA
 
Clojure programming-chapter-2
Clojure programming-chapter-2Clojure programming-chapter-2
Clojure programming-chapter-2Masao Kato
 
やや関数型を意識した風Elixir/Phoenixご紹介
やや関数型を意識した風Elixir/Phoenixご紹介やや関数型を意識した風Elixir/Phoenixご紹介
やや関数型を意識した風Elixir/Phoenixご紹介fukuoka.ex
 
jQuery Performance Tips – jQueryにおける高速化 -
jQuery Performance Tips – jQueryにおける高速化 -jQuery Performance Tips – jQueryにおける高速化 -
jQuery Performance Tips – jQueryにおける高速化 -Hayato Mizuno
 
メタメタプログラミングRuby
メタメタプログラミングRubyメタメタプログラミングRuby
メタメタプログラミングRubyemasaka
 
思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8
思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8
思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8y_taka_23
 
(Ruby使いのための)Scalaで学ぶ関数型プログラミング
(Ruby使いのための)Scalaで学ぶ関数型プログラミング(Ruby使いのための)Scalaで学ぶ関数型プログラミング
(Ruby使いのための)Scalaで学ぶ関数型プログラミングOuka Yuka
 
Functional JavaScript with Lo-Dash.js
Functional JavaScript with Lo-Dash.jsFunctional JavaScript with Lo-Dash.js
Functional JavaScript with Lo-Dash.jsShogo Sensui
 
第三回ありえる社内勉強会 「いわががのLombok」
第三回ありえる社内勉強会 「いわががのLombok」第三回ありえる社内勉強会 「いわががのLombok」
第三回ありえる社内勉強会 「いわががのLombok」yoshiaki iwanaga
 
for JSDeferred Code Reading
for JSDeferred Code Readingfor JSDeferred Code Reading
for JSDeferred Code ReadingKenichirou Oyama
 
Sns suite presentation
Sns suite presentationSns suite presentation
Sns suite presentationJason Namkung
 
20110820 metaprogramming
20110820 metaprogramming20110820 metaprogramming
20110820 metaprogrammingMasanori Kado
 

Similar to Everyday Life with clojure.spec (20)

Scalamacrosについて
ScalamacrosについてScalamacrosについて
Scalamacrosについて
 
Lisp batton - Common LISP
Lisp batton - Common LISPLisp batton - Common LISP
Lisp batton - Common LISP
 
Clojure programming-chapter-2
Clojure programming-chapter-2Clojure programming-chapter-2
Clojure programming-chapter-2
 
Clojure
ClojureClojure
Clojure
 
Scala on Hadoop
Scala on HadoopScala on Hadoop
Scala on Hadoop
 
Haskell超入門 Part.1
Haskell超入門 Part.1Haskell超入門 Part.1
Haskell超入門 Part.1
 
やや関数型を意識した風Elixir/Phoenixご紹介
やや関数型を意識した風Elixir/Phoenixご紹介やや関数型を意識した風Elixir/Phoenixご紹介
やや関数型を意識した風Elixir/Phoenixご紹介
 
jQuery Performance Tips – jQueryにおける高速化 -
jQuery Performance Tips – jQueryにおける高速化 -jQuery Performance Tips – jQueryにおける高速化 -
jQuery Performance Tips – jQueryにおける高速化 -
 
メタメタプログラミングRuby
メタメタプログラミングRubyメタメタプログラミングRuby
メタメタプログラミングRuby
 
思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8
思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8
思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8
 
Pfi Seminar 2010 1 7
Pfi Seminar 2010 1 7Pfi Seminar 2010 1 7
Pfi Seminar 2010 1 7
 
(Ruby使いのための)Scalaで学ぶ関数型プログラミング
(Ruby使いのための)Scalaで学ぶ関数型プログラミング(Ruby使いのための)Scalaで学ぶ関数型プログラミング
(Ruby使いのための)Scalaで学ぶ関数型プログラミング
 
Functional JavaScript with Lo-Dash.js
Functional JavaScript with Lo-Dash.jsFunctional JavaScript with Lo-Dash.js
Functional JavaScript with Lo-Dash.js
 
ATN No.2 Scala事始め
ATN No.2 Scala事始めATN No.2 Scala事始め
ATN No.2 Scala事始め
 
第三回ありえる社内勉強会 「いわががのLombok」
第三回ありえる社内勉強会 「いわががのLombok」第三回ありえる社内勉強会 「いわががのLombok」
第三回ありえる社内勉強会 「いわががのLombok」
 
for JSDeferred Code Reading
for JSDeferred Code Readingfor JSDeferred Code Reading
for JSDeferred Code Reading
 
Sns suite presentation
Sns suite presentationSns suite presentation
Sns suite presentation
 
Haskell で CLI
Haskell で CLIHaskell で CLI
Haskell で CLI
 
20110820 metaprogramming
20110820 metaprogramming20110820 metaprogramming
20110820 metaprogramming
 
GraphQL入門
GraphQL入門GraphQL入門
GraphQL入門
 

More from Kent Ohashi

インターフェース定義言語から学ぶモダンなWeb API方式: REST, GraphQL, gRPC
インターフェース定義言語から学ぶモダンなWeb API方式: REST, GraphQL, gRPCインターフェース定義言語から学ぶモダンなWeb API方式: REST, GraphQL, gRPC
インターフェース定義言語から学ぶモダンなWeb API方式: REST, GraphQL, gRPCKent Ohashi
 
Team Geek Revisited
Team Geek RevisitedTeam Geek Revisited
Team Geek RevisitedKent Ohashi
 
Scala vs Clojure?: The Rise and Fall of Functional Languages in Opt Technologies
Scala vs Clojure?: The Rise and Fall of Functional Languages in Opt TechnologiesScala vs Clojure?: The Rise and Fall of Functional Languages in Opt Technologies
Scala vs Clojure?: The Rise and Fall of Functional Languages in Opt TechnologiesKent Ohashi
 
Clojureコレクションで探るimmutableでpersistentな世界
Clojureコレクションで探るimmutableでpersistentな世界Clojureコレクションで探るimmutableでpersistentな世界
Clojureコレクションで探るimmutableでpersistentな世界Kent Ohashi
 
英語学習者のためのフランス語文法入門: フランス語完全理解(?)
英語学習者のためのフランス語文法入門: フランス語完全理解(?)英語学習者のためのフランス語文法入門: フランス語完全理解(?)
英語学習者のためのフランス語文法入門: フランス語完全理解(?)Kent Ohashi
 
実用のための語源学入門
実用のための語源学入門実用のための語源学入門
実用のための語源学入門Kent Ohashi
 
メタプログラミング入門
メタプログラミング入門メタプログラミング入門
メタプログラミング入門Kent Ohashi
 
労働法の世界
労働法の世界労働法の世界
労働法の世界Kent Ohashi
 
Clojureで作る"simple"なDSL
Clojureで作る"simple"なDSLClojureで作る"simple"なDSL
Clojureで作る"simple"なDSLKent Ohashi
 
RDBでのツリー表現入門
RDBでのツリー表現入門RDBでのツリー表現入門
RDBでのツリー表現入門Kent Ohashi
 
たのしい多言語学習
たのしい多言語学習たのしい多言語学習
たのしい多言語学習Kent Ohashi
 
Ductモジュール入門
Ductモジュール入門Ductモジュール入門
Ductモジュール入門Kent Ohashi
 
Clojure REPL: The Good Parts
Clojure REPL: The Good PartsClojure REPL: The Good Parts
Clojure REPL: The Good PartsKent Ohashi
 
Clojurian Conquest
Clojurian ConquestClojurian Conquest
Clojurian ConquestKent Ohashi
 
ClojurianからみたElixir
ClojurianからみたElixirClojurianからみたElixir
ClojurianからみたElixirKent Ohashi
 
GraphQL API in Clojure
GraphQL API in ClojureGraphQL API in Clojure
GraphQL API in ClojureKent Ohashi
 
Interceptors: Into the Core of Pedestal
Interceptors: Into the Core of PedestalInterceptors: Into the Core of Pedestal
Interceptors: Into the Core of PedestalKent Ohashi
 
Boost your productivity with Clojure REPL
Boost your productivity with Clojure REPLBoost your productivity with Clojure REPL
Boost your productivity with Clojure REPLKent Ohashi
 
ClojureScript: The Good Parts
ClojureScript: The Good PartsClojureScript: The Good Parts
ClojureScript: The Good PartsKent Ohashi
 

More from Kent Ohashi (20)

インターフェース定義言語から学ぶモダンなWeb API方式: REST, GraphQL, gRPC
インターフェース定義言語から学ぶモダンなWeb API方式: REST, GraphQL, gRPCインターフェース定義言語から学ぶモダンなWeb API方式: REST, GraphQL, gRPC
インターフェース定義言語から学ぶモダンなWeb API方式: REST, GraphQL, gRPC
 
Team Geek Revisited
Team Geek RevisitedTeam Geek Revisited
Team Geek Revisited
 
Scala vs Clojure?: The Rise and Fall of Functional Languages in Opt Technologies
Scala vs Clojure?: The Rise and Fall of Functional Languages in Opt TechnologiesScala vs Clojure?: The Rise and Fall of Functional Languages in Opt Technologies
Scala vs Clojure?: The Rise and Fall of Functional Languages in Opt Technologies
 
Clojureコレクションで探るimmutableでpersistentな世界
Clojureコレクションで探るimmutableでpersistentな世界Clojureコレクションで探るimmutableでpersistentな世界
Clojureコレクションで探るimmutableでpersistentな世界
 
英語学習者のためのフランス語文法入門: フランス語完全理解(?)
英語学習者のためのフランス語文法入門: フランス語完全理解(?)英語学習者のためのフランス語文法入門: フランス語完全理解(?)
英語学習者のためのフランス語文法入門: フランス語完全理解(?)
 
実用のための語源学入門
実用のための語源学入門実用のための語源学入門
実用のための語源学入門
 
メタプログラミング入門
メタプログラミング入門メタプログラミング入門
メタプログラミング入門
 
労働法の世界
労働法の世界労働法の世界
労働法の世界
 
Clojureで作る"simple"なDSL
Clojureで作る"simple"なDSLClojureで作る"simple"なDSL
Clojureで作る"simple"なDSL
 
RDBでのツリー表現入門
RDBでのツリー表現入門RDBでのツリー表現入門
RDBでのツリー表現入門
 
たのしい多言語学習
たのしい多言語学習たのしい多言語学習
たのしい多言語学習
 
Ductモジュール入門
Ductモジュール入門Ductモジュール入門
Ductモジュール入門
 
Clojure REPL: The Good Parts
Clojure REPL: The Good PartsClojure REPL: The Good Parts
Clojure REPL: The Good Parts
 
Clojurian Conquest
Clojurian ConquestClojurian Conquest
Clojurian Conquest
 
ClojurianからみたElixir
ClojurianからみたElixirClojurianからみたElixir
ClojurianからみたElixir
 
GraphQL API in Clojure
GraphQL API in ClojureGraphQL API in Clojure
GraphQL API in Clojure
 
法学入門
法学入門法学入門
法学入門
 
Interceptors: Into the Core of Pedestal
Interceptors: Into the Core of PedestalInterceptors: Into the Core of Pedestal
Interceptors: Into the Core of Pedestal
 
Boost your productivity with Clojure REPL
Boost your productivity with Clojure REPLBoost your productivity with Clojure REPL
Boost your productivity with Clojure REPL
 
ClojureScript: The Good Parts
ClojureScript: The Good PartsClojureScript: The Good Parts
ClojureScript: The Good Parts
 

Everyday Life with clojure.spec