SlideShare una empresa de Scribd logo
1 de 47
Descargar para leer sin conexión
Spectacular	Future
with	clojure.spec
Self-introduction
	/laʒenɔʁɛ̃k/	カマイルカlagénorhynque
(defprofile lagénorhynque
:name "Kent OHASHI"
:languages [Clojure Haskell Python Scala
English français Deutsch русский]
:interests [programming language-learning mathematics]
:contributing [github.com/japan-clojurians/clojure-site-ja])
「Clojureをプロダクトに導⼊した話」
Clojure
Contents
1.	 Clojure	Quick	Intro
2.	 New	Feature:	clojure.spec
Clojure	Quick	Intro
Clojure
Lisp
S式,	マクロ,	etc.
REPL駆動開発
関数型プログラミング⾔語
動的⾔語
JVM⾔語	(cf.	ClojureScript)
⇒	シンプルで強⼒な⾔語
リテラル
type example
string "abc"
character a
number 1,	2.0,	3N,	4.5M,	6/7,	8r10
boolean true,	false
nil nil
keyword :a,	:user/a,	::a,	::x/a
symbol 'a,	'user/a,	`a,	`x/a
type example
list '(1 2 3),	'(+ 1 2 3)
vector [1 2 3]
set #{1 2 3}
map {:a 1 :b 2},	#:user{:a 1 :b 2},
#::{:a 1 :b 2},	#::x{:a 1 :b 2}
function (fn [x] (* x x))
シンタックス
オペレータ
関数
マクロ
特殊形式
(op arg1 arg2 ... argn)
New	Feature:
clojure.spec
例:	直⽅体の体積計算
直⽅体の体積	=	辺a	×	辺b	×	辺c
user> (defn cuboid-volume [{:keys [side-a side-b side-c]}]
(* side-a side-b side-c))
#'user/cuboid-volume
user> (cuboid-volume {:side-a 1 :side-b 2 :side-c 3})
6
エラー
Javaのスタックトレースが\(^o^)/……
;; マップの値の型が数値ではなく⽂字列
user> (cuboid-volume {:side-a 1 :side-b "2" :side-c 3})
ClassCastException java.lang.String cannot be cast to java.lang.
Number clojure.lang.Numbers.multiply (Numbers.java:148)
;; マップのキー名でtypo
user> (cuboid-volume {:side-a 1 :side-d 2 :side-c 3})
NullPointerException clojure.lang.Numbers.ops (Numbers.java:10
18)
;; マップに必須のキーがない
user> (cuboid-volume {:side-a 1 :side-c 3})
NullPointerException clojure.lang.Numbers.ops (Numbers.java:10
18)
問題点
動的⾔語なのでコンパイル時に引数の型の不整合が
検出されない
少なくとも実⾏時に分かりやすいエラーになって
ほしい
マップのkey-valueに対するチェックがない
動的なデータを柔軟に表現したい
cf.	
漸進的型付け(gradual	typing)
Clojureに静的型システムを追加
コンパイル時に型チェック
core.typed
(require '[clojure.core.typed :as t])
(t/ann cuboid-volume [(t/HMap :mandatory {:side-a t/Num
:side-b t/Num
:side-c t/Num})
:-> t/Num])
(defn cuboid-volume [{:keys [side-a side-b side-c]}]
(* side-a side-b side-c))
cf.	
データ記述/バリデーションDSL
独⾃DSLでデータ構造を表現
実⾏時にバリデーション
schema
(require '[schema.core :as s])
(s/defn cuboid-volume :- s/Num
[{:keys [side-a side-b side-c]} :- {:side-a s/Num
:side-b s/Num
:side-c s/Num}]
(* side-a side-b side-c))
clojure.spec
述語(predicate)を組み合わせて仕様(spec)を書いて
ドキュメント
バリデーション
詳細なエラー報告
パースと分配束縛
データ⽣成
プロパティベーストテスト
などを実現する仕組み
dependency
REPL
[org.clojure/clojure "1.9.0-beta1"]
user> (require '[clojure.spec.alpha :as s]
'[clojure.spec.test.alpha :as stest]
'[clojure.spec.gen.alpha :as gen])
nil
「⻑さ」をspecで表現
	でキーワード	:user/length	に述語
number?	を登録
user> (s/def ::length number?)
:user/length
user> (doc ::length)
-------------------------
:user/length
Spec
number?
nil
s/def
「⻑さ」に⼀致する値を調べる
	で	::length	のspecに具体的な値が
⼀致するか確認
⼀致しなければ	::s/invalid
user> (s/conform ::length 3)
3
user> (s/conform ::length "3")
:clojure.spec.alpha/invalid
s/conform
⼀致しない原因を調べる
	で⼀致しない詳細原因を確認
ここでは
値	"3"	がspec	:user/length	の述語	number?
に不⼀致
user> (s/explain ::length "3")
val: "3" fails spec: :user/length predicate: number?
:clojure.spec.alpha/spec :user/length
:clojure.spec.alpha/value "3"
nil
s/explain
「⻑さ」のサンプルを⽣成
	で	 	互換なジェネレータを取得
	でサンプルを⽣成
user> (s/gen ::length)
#clojure.test.check.generators.Generator{:gen #function[clojure.
test.check.generators/such-that/fn--13745]}
user> (gen/sample (s/gen ::length))
(0.5 -1.0 -1 0.5 3.25 0 -3 0.6875 0.25 0)
s/gen test.check
gen/sample
「⻑さ」に制約を加える
論理演算⼦で制約を追加
	は論理積
cf.	
user> (s/def ::length (s/and number? pos?))
:user/length
user> (doc ::length)
-------------------------
:user/length
Spec
(and number? pos?)
nil
user> (gen/sample (s/gen ::length))
(0.5 3.0 0.5 1.375 1.6875 3.0 0.625 1.25 0.41015625 0.25)
s/and
s/or
「⻑さ」で辺a,	b,	cを表現
user> (s/def ::side-a ::length)
:user/side-a
user> (doc ::side-a)
-------------------------
:user/side-a
Spec
(and number? pos?)
nil
user> (s/def ::side-b ::length)
:user/side-b
user> (s/def ::side-c ::length)
:user/side-c
辺a,	b,	cを持つマップとして直⽅体
を表現
	で必須のキーを持つマップを表現
user> (s/def ::cuboid (s/keys :req [::side-a ::side-b ::side-c])
)
:user/cuboid
user> (doc ::cuboid)
-------------------------
:user/cuboid
Spec
(keys :req [:user/side-a :user/side-b :user/side-c])
nil
s/keys
直⽅体に⼀致する値を調べる
user> (s/conform ::cuboid #::{:side-a 1
:side-b 2
:side-c 3})
#:user{:side-a 1, :side-b 2, :side-c 3}
user> (s/conform ::cuboid #::{:side-a 1
:side-b "2"
:side-c 3})
:clojure.spec.alpha/invalid
⼀致しない原因を調べる
:user/side-b	の値	"2"	がspec	:user/length
の述語	number?	に不⼀致
マップのキーに対応するspecもチェックされる
user> (s/explain ::cuboid #::{:side-a 1
:side-b "2"
:side-c 3})
In: [:user/side-b] val: "2" fails spec: :user/length at: [:user/
side-b] predicate: number?
:clojure.spec.alpha/spec :user/cuboid
:clojure.spec.alpha/value #:user{:side-a 1, :side-b "2", :side-
c 3}
nil
値	#:user{:side-a 1, :side-d 2, :side-c
3}	がspec	:user/cuboid	の述語	(contains? %
:user/side-b)	に不⼀致
user> (s/explain ::cuboid #::{:side-a 1
:side-d 2
:side-c 3})
val: #:user{:side-a 1, :side-d 2, :side-c 3} fails spec: :user/c
uboid predicate: (contains? % :user/side-b)
:clojure.spec.alpha/spec :user/cuboid
:clojure.spec.alpha/value #:user{:side-a 1, :side-d 2, :side-c
3}
nil
値	#:user{:side-a 1, :side-c 3}	がspec
:user/cuboid	の述語	(contains? %
:user/side-b)	に不⼀致
user> (s/explain ::cuboid #::{:side-a 1
:side-c 3})
val: #:user{:side-a 1, :side-c 3} fails spec: :user/cuboid predi
cate: (contains? % :user/side-b)
:clojure.spec.alpha/spec :user/cuboid
:clojure.spec.alpha/value #:user{:side-a 1, :side-c 3}
nil
直⽅体のサンプルを⽣成
複合的なデータのサンプルも⽣成できる
user> (gen/sample (s/gen ::cuboid))
(#:user{:side-a 0.5, :side-b 1.0, :side-c 0.625} #:user{:side-a
0.5, :side-b 1.5, :side-c 2} #:user{:side-a 2.0, :side-b 4, :sid
e-c 1} #:user{:side-a 1.5, :side-b 1.0, :side-c 1} #:user{:side-
a 0.5, :side-b 12, :side-c 1.125} #:user{:side-a 49, :side-b 0.3
59375, :side-c 0.765625} #:user{:side-a 2, :side-b 1, :side-c 1.
25} #:user{:side-a 3.0, :side-b 0.5, :side-c 2.0} #:user{:side-a
1.3125, :side-b 1.0, :side-c 1.0} #:user{:side-a 5.265625, :sid
e-b 1.0625, :side-c 2.73828125})
直⽅体の体積計算の仕様を表現
	で関数	cuboid-volume	の引数と戻り値
に対するspecを登録
引数:	::cuboid	1要素のシーケンス
	は正規表現演算⼦
cf.	 ,	 ,	 ,	 ,	
戻り値:	数値
user> (s/fdef cuboid-volume
:args (s/cat :cuboid ::cuboid)
:ret number?)
user/cuboid-volume
s/fdef
s/cat
s/* s/+ s/? s/& s/alt
仕様を満たすように関数を実装
user> (defn cuboid-volume [{::keys [side-a side-b side-c]}]
(* side-a side-b side-c))
#'user/cuboid-volume
引数に対するチェックを有効化
stest/instrument
user> (doc cuboid-volume)
-------------------------
user/cuboid-volume
([#:user{:keys [side-a side-b side-c]}])
Spec
args: (cat :cuboid :user/cuboid)
ret: number?
nil
user> (stest/instrument)
[user/cuboid-volume]
引数のspecを満たす値に適⽤すると期待した計算
結果が得られる
user> (cuboid-volume #::{:side-a 1
:side-b 2
:side-c 3})
6
パス	[0 :user/side-b]	の値	"2"	がspec
:user/length	の述語	number?	に不⼀致	⇒	例外
user> (cuboid-volume #::{:side-a 1
:side-b "2"
:side-c 3})
ExceptionInfo Call to #'user/cuboid-volume did not conform to sp
ec:
In: [0 :user/side-b] val: "2" fails spec: :user/length at: [:arg
s :cuboid :user/side-b] predicate: number?
:clojure.spec.alpha/spec #object[clojure.spec.alpha$regex_spec_
impl$reify__1200 0x57e771b6 "clojure.spec.alpha$regex_spec_impl$
reify__1200@57e771b6"]
:clojure.spec.alpha/value (#:user{:side-a 1, :side-b "2", :side
-c 3})
:clojure.spec.alpha/args (#:user{:side-a 1, :side-b "2", :side-
c 3})
:clojure.spec.alpha/failure :instrument
:clojure.spec.test.alpha/caller {:file "form-init41134222269549
81451.clj", :line 188, :var-scope user/eval14130}
clojure.core/ex-info (core.clj:4744)
関数の動作確認
	で引数のspecを満たすランダム
な値で動作確認
結果はベクター	[引数 戻り値]	のシーケンス
user> (s/exercise-fn `cuboid-volume)
([(#:user{:side-a 2.0, :side-b 0.5, :side-c 0.5}) 0.5] [(#:user{
:side-a 0.75, :side-b 1.5, :side-c 0.75}) 0.84375] [(#:user{:sid
e-a 2.0, :side-b 1, :side-c 1.75}) 3.5] [(#:user{:side-a 4, :sid
e-b 4, :side-c 2}) 32] [(#:user{:side-a 2, :side-b 6, :side-c 1.
0}) 12.0] [(#:user{:side-a 1, :side-b 3, :side-c 6}) 18] [(#:use
r{:side-a 20, :side-b 1.0, :side-c 99}) 1980.0] [(#:user{:side-a
12, :side-b 890, :side-c 1.25}) 13350.0] [(#:user{:side-a 4, :s
ide-b 0.99609375, :side-c 2.0}) 7.96875] [(#:user{:side-a 3, :si
de-b 6.0, :side-c 9}) 162.0])
s/exercise-fn
⾃動プロパティベーストテスト
stest/check
user> (stest/check `cuboid-volume)
({:spec #object[clojure.spec.alpha$fspec_impl$reify__1215 0x765acd43 "c
:cause "integer overflow"
:via
[{:type java.lang.ArithmeticException
:message "integer overflow"
:at [clojure.lang.Numbers throwIntOverflow "Numbers.java" 1526]}]
:trace
[[clojure.lang.Numbers throwIntOverflow "Numbers.java" 1526]
[clojure.lang.Numbers multiply "Numbers.java" 1892]
[clojure.lang.Numbers$LongOps multiply "Numbers.java" 472]
[clojure.lang.Numbers multiply "Numbers.java" 148]
[user$cuboid_volume invokeStatic "form-init4113422226954981451.clj" 1
[user$cuboid_volume invoke "form-init4113422226954981451.clj" 155]
[clojure.lang.AFn applyToHelper "AFn.java" 154]
[clojure.lang.AFn applyTo "AFn.java" 144]
[clojure.core$apply invokeStatic "core.clj" 657]
[clojure.core$apply invoke "core.clj" 652]
[clojure.spec.test.alpha$check_call invokeStatic "alpha.clj" 292]
ここでは
乗算でinteger	overflowが発⽣しうることが判明
:smallest	[(#:user{:side-a	1,	:side-b
23021144,	:side-c	400647858198})]
user> (cuboid-volume #::{:side-a 1
:side-b 23021144
:side-c 400647858198})
ArithmeticException integer overflow clojure.lang.Numbers.throw
IntOverflow (Numbers.java:1526)
integer	overflowしないように関数	*	を	*'	に変更
user> (defn cuboid-volume [{::keys [side-a side-b side-c]}]
(*' side-a side-b side-c))
#'user/cuboid-volume
user> (cuboid-volume #::{:side-a 1
:side-b 23021144
:side-c 400647858198})
9223372036867738512N
デフォルト1000回の試⾏で正常にテストをパス
user> (stest/check `cuboid-volume)
({:spec #object[clojure.spec.alpha$fspec_impl$reify__1215 0x765a
cd43 "clojure.spec.alpha$fspec_impl$reify__1215@765acd43"], :clo
jure.spec.test.check/ret {:result true, :num-tests 1000, :seed 1
505803853835}, :sym user/cuboid-volume})
user> (stest/summarize-results *1)
{:sym user/cuboid-volume}
{:total 1, :check-passed 1}
最終結果
(ns spec-examples.geometry
(:require [clojure.spec.alpha :as s]))
;; specs
(s/def ::length (s/and number? pos?))
(s/def ::side-a ::length)
(s/def ::side-b ::length)
(s/def ::side-c ::length)
(s/def ::cuboid (s/keys :req [::side-a ::side-b ::side-c])
(s/fdef cuboid-volume
:args (s/cat :cuboid ::cuboid)
:ret number?)
;; implementation
(defn cuboid-volume [{::keys [side-a side-b side-c]}]
(*' side-a side-b side-c))
述語(predicate)で仕様が書ける
値に対する制約が柔軟に表現できる
Clojureの動的な性質と親和性が⾮常に⾼い
コンパイル時ではなく実⾏時
REPL駆動開発とプロパティベーストテストで制
約を満たしていることを保証する戦略
漸進的型付け/静的⾔語化とは異なる未来
⾃動プロパティベーストテストが便利
clojure.specを活⽤して
変更に強いClojureコードを書こう
(*> ᴗ •*)ゞ
Vive	les	S-expressions	!
Long	live	S-expressions!
Further	Reading
example	code
lagenorhynque/spec-examples
clojure.spec	vs	core.typed	vs	schema
of cial	site
clojure.spec	-	Rationale	and	Overview
spec	Guide
clojure/clojure	at	clojure-1.9.0-beta1
clojure/spec.alpha
clojure.spec	-	Clojure	v1.9	API
documentation
clojure/core.specs.alpha
clojure/core.typed
plumatic/schema
video
book
Spec-ulation	Keynote	-	Rich	Hickey
"Agility	&	Robustness:	Clojure	spec"	by	Stuart
Halloway
clojure.spec	-	David	Nolen
Clojure	spec	Screencast	Series
Programming	Clojure,	Third	Edition

Más contenido relacionado

La actualidad más candente

Twitterのsnowflakeについて
TwitterのsnowflakeについてTwitterのsnowflakeについて
Twitterのsnowflakeについて
moai kids
 
オブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツオブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツ
増田 亨
 
Goのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考える
Goのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考えるGoのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考える
Goのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考える
pospome
 

La actualidad más candente (20)

イミュータブルデータモデルの極意
イミュータブルデータモデルの極意イミュータブルデータモデルの極意
イミュータブルデータモデルの極意
 
Java ORマッパー選定のポイント #jsug
Java ORマッパー選定のポイント #jsugJava ORマッパー選定のポイント #jsug
Java ORマッパー選定のポイント #jsug
 
世界一わかりやすいClean Architecture
世界一わかりやすいClean Architecture世界一わかりやすいClean Architecture
世界一わかりやすいClean Architecture
 
オススメの標準・準標準パッケージ20選
オススメの標準・準標準パッケージ20選オススメの標準・準標準パッケージ20選
オススメの標準・準標準パッケージ20選
 
これで怖くない!?コードリーディングで学ぶSpring Security #中央線Meetup
これで怖くない!?コードリーディングで学ぶSpring Security #中央線Meetupこれで怖くない!?コードリーディングで学ぶSpring Security #中央線Meetup
これで怖くない!?コードリーディングで学ぶSpring Security #中央線Meetup
 
Dockerfileを改善するためのBest Practice 2019年版
Dockerfileを改善するためのBest Practice 2019年版Dockerfileを改善するためのBest Practice 2019年版
Dockerfileを改善するためのBest Practice 2019年版
 
ネットストーカー御用達OSINTツールBlackBirdを触ってみた.pptx
ネットストーカー御用達OSINTツールBlackBirdを触ってみた.pptxネットストーカー御用達OSINTツールBlackBirdを触ってみた.pptx
ネットストーカー御用達OSINTツールBlackBirdを触ってみた.pptx
 
エンジニアの個人ブランディングと技術組織
エンジニアの個人ブランディングと技術組織エンジニアの個人ブランディングと技術組織
エンジニアの個人ブランディングと技術組織
 
Confluence と DITA による Webマニュアル作成フロー
Confluence と DITA によるWebマニュアル作成フローConfluence と DITA によるWebマニュアル作成フロー
Confluence と DITA による Webマニュアル作成フロー
 
Twitterのsnowflakeについて
TwitterのsnowflakeについてTwitterのsnowflakeについて
Twitterのsnowflakeについて
 
イミュータブルデータモデル(入門編)
イミュータブルデータモデル(入門編)イミュータブルデータモデル(入門編)
イミュータブルデータモデル(入門編)
 
オブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツオブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツ
 
DBスキーマもバージョン管理したい!
DBスキーマもバージョン管理したい!DBスキーマもバージョン管理したい!
DBスキーマもバージョン管理したい!
 
emscriptenでC/C++プログラムをwebブラウザから使うまでの難所攻略
emscriptenでC/C++プログラムをwebブラウザから使うまでの難所攻略emscriptenでC/C++プログラムをwebブラウザから使うまでの難所攻略
emscriptenでC/C++プログラムをwebブラウザから使うまでの難所攻略
 
やはりお前らのMVCは間違っている
やはりお前らのMVCは間違っているやはりお前らのMVCは間違っている
やはりお前らのMVCは間違っている
 
Goのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考える
Goのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考えるGoのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考える
Goのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考える
 
DockerコンテナでGitを使う
DockerコンテナでGitを使うDockerコンテナでGitを使う
DockerコンテナでGitを使う
 
#logstudy 01 rsyslog入門
#logstudy 01 rsyslog入門#logstudy 01 rsyslog入門
#logstudy 01 rsyslog入門
 
URLで遊ぼう
URLで遊ぼうURLで遊ぼう
URLで遊ぼう
 
基礎からのOAuth 2.0とSpring Security 5.1による実装
基礎からのOAuth 2.0とSpring Security 5.1による実装基礎からのOAuth 2.0とSpring Security 5.1による実装
基礎からのOAuth 2.0とSpring Security 5.1による実装
 

Similar a Spectacular Future with clojure.spec

TypeScript 1.0 オーバービュー
TypeScript 1.0 オーバービューTypeScript 1.0 オーバービュー
TypeScript 1.0 オーバービュー
Akira Inoue
 
TypeScript ファーストステップ (Rev.2) ~ Any browser. Any host. Any OS. Open Source. ~
TypeScript ファーストステップ (Rev.2) ~ Any browser. Any host. Any OS. Open Source. ~TypeScript ファーストステップ (Rev.2) ~ Any browser. Any host. Any OS. Open Source. ~
TypeScript ファーストステップ (Rev.2) ~ Any browser. Any host. Any OS. Open Source. ~
Akira Inoue
 
Visual Studio 2012 Web 開発 ~ One ASP.NET から TypeScript まで ~
Visual Studio 2012 Web 開発 ~ One ASP.NET から TypeScript まで ~Visual Studio 2012 Web 開発 ~ One ASP.NET から TypeScript まで ~
Visual Studio 2012 Web 開発 ~ One ASP.NET から TypeScript まで ~
Akira Inoue
 
Inside of excel 方眼紙撲滅委員会 #pyfes
Inside of excel 方眼紙撲滅委員会 #pyfesInside of excel 方眼紙撲滅委員会 #pyfes
Inside of excel 方眼紙撲滅委員会 #pyfes
Takeshi Komiya
 
TypeScript ファーストステップ ~ Any browser. Any host. Any OS. Open Source. ~
TypeScript ファーストステップ ~ Any browser. Any host. Any OS. Open Source. ~TypeScript ファーストステップ ~ Any browser. Any host. Any OS. Open Source. ~
TypeScript ファーストステップ ~ Any browser. Any host. Any OS. Open Source. ~
Akira Inoue
 
More Better Nested Set
More Better Nested SetMore Better Nested Set
More Better Nested Set
xibbar
 
Ruby Postgres 2009
Ruby Postgres 2009Ruby Postgres 2009
Ruby Postgres 2009
Akio Ishida
 

Similar a Spectacular Future with clojure.spec (20)

Everyday Life with clojure.spec
Everyday Life with clojure.specEveryday Life with clojure.spec
Everyday Life with clojure.spec
 
TypeScript 1.0 オーバービュー
TypeScript 1.0 オーバービューTypeScript 1.0 オーバービュー
TypeScript 1.0 オーバービュー
 
計算機理論入門09
計算機理論入門09計算機理論入門09
計算機理論入門09
 
TypeScript ファーストステップ (Rev.2) ~ Any browser. Any host. Any OS. Open Source. ~
TypeScript ファーストステップ (Rev.2) ~ Any browser. Any host. Any OS. Open Source. ~TypeScript ファーストステップ (Rev.2) ~ Any browser. Any host. Any OS. Open Source. ~
TypeScript ファーストステップ (Rev.2) ~ Any browser. Any host. Any OS. Open Source. ~
 
Pfi Seminar 2010 1 7
Pfi Seminar 2010 1 7Pfi Seminar 2010 1 7
Pfi Seminar 2010 1 7
 
Visual Studio 2012 Web 開発 ~ One ASP.NET から TypeScript まで ~
Visual Studio 2012 Web 開発 ~ One ASP.NET から TypeScript まで ~Visual Studio 2012 Web 開発 ~ One ASP.NET から TypeScript まで ~
Visual Studio 2012 Web 開発 ~ One ASP.NET から TypeScript まで ~
 
Okinawa.rb 第2回勉強会
Okinawa.rb 第2回勉強会Okinawa.rb 第2回勉強会
Okinawa.rb 第2回勉強会
 
Inside of excel 方眼紙撲滅委員会 #pyfes
Inside of excel 方眼紙撲滅委員会 #pyfesInside of excel 方眼紙撲滅委員会 #pyfes
Inside of excel 方眼紙撲滅委員会 #pyfes
 
TypeScript ファーストステップ ~ Any browser. Any host. Any OS. Open Source. ~
TypeScript ファーストステップ ~ Any browser. Any host. Any OS. Open Source. ~TypeScript ファーストステップ ~ Any browser. Any host. Any OS. Open Source. ~
TypeScript ファーストステップ ~ Any browser. Any host. Any OS. Open Source. ~
 
var RAC3 = ReactiveCocoa + Swift @ ReactiveCocoa Tokyo #rac_tokyo 10/18
var RAC3 = ReactiveCocoa + Swift @ ReactiveCocoa Tokyo #rac_tokyo 10/18var RAC3 = ReactiveCocoa + Swift @ ReactiveCocoa Tokyo #rac_tokyo 10/18
var RAC3 = ReactiveCocoa + Swift @ ReactiveCocoa Tokyo #rac_tokyo 10/18
 
Pub/Sub model, msm, and asio
Pub/Sub model, msm, and asioPub/Sub model, msm, and asio
Pub/Sub model, msm, and asio
 
Objc lambda
Objc lambdaObjc lambda
Objc lambda
 
More Better Nested Set
More Better Nested SetMore Better Nested Set
More Better Nested Set
 
きつねさんでもわかるLlvm読書会 第2回
きつねさんでもわかるLlvm読書会 第2回きつねさんでもわかるLlvm読書会 第2回
きつねさんでもわかるLlvm読書会 第2回
 
第四回 JavaScriptから始めるプログラミング2016
第四回 JavaScriptから始めるプログラミング2016第四回 JavaScriptから始めるプログラミング2016
第四回 JavaScriptから始めるプログラミング2016
 
VerilatorとSystemC
VerilatorとSystemCVerilatorとSystemC
VerilatorとSystemC
 
EWD 3トレーニングコース#19 JavaScriptからGlobalストレジにアクセスする
EWD 3トレーニングコース#19 JavaScriptからGlobalストレジにアクセスするEWD 3トレーニングコース#19 JavaScriptからGlobalストレジにアクセスする
EWD 3トレーニングコース#19 JavaScriptからGlobalストレジにアクセスする
 
Ruby Postgres 2009
Ruby Postgres 2009Ruby Postgres 2009
Ruby Postgres 2009
 
Scala on Hadoop
Scala on HadoopScala on Hadoop
Scala on Hadoop
 
TypeScript と Visual Studio Code
TypeScript と Visual Studio CodeTypeScript と Visual Studio Code
TypeScript と Visual Studio Code
 

Más de Kent Ohashi

Más de 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な世界
 
英語学習者のためのフランス語文法入門: フランス語完全理解(?)
英語学習者のためのフランス語文法入門: フランス語完全理解(?)英語学習者のためのフランス語文法入門: フランス語完全理解(?)
英語学習者のためのフランス語文法入門: フランス語完全理解(?)
 
JavaからScala、そしてClojureへ: 実務で活きる関数型プログラミング
JavaからScala、そしてClojureへ: 実務で活きる関数型プログラミングJavaからScala、そしてClojureへ: 実務で活きる関数型プログラミング
JavaからScala、そしてClojureへ: 実務で活きる関数型プログラミング
 
実用のための語源学入門
実用のための語源学入門実用のための語源学入門
実用のための語源学入門
 
メタプログラミング入門
メタプログラミング入門メタプログラミング入門
メタプログラミング入門
 
労働法の世界
労働法の世界労働法の世界
労働法の世界
 
Clojureで作る"simple"なDSL
Clojureで作る"simple"なDSLClojureで作る"simple"なDSL
Clojureで作る"simple"なDSL
 
RDBでのツリー表現入門
RDBでのツリー表現入門RDBでのツリー表現入門
RDBでのツリー表現入門
 
GraphQL入門
GraphQL入門GraphQL入門
GraphQL入門
 
たのしい多言語学習
たのしい多言語学習たのしい多言語学習
たのしい多言語学習
 
Ductモジュール入門
Ductモジュール入門Ductモジュール入門
Ductモジュール入門
 
Clojure REPL: The Good Parts
Clojure REPL: The Good PartsClojure REPL: The Good Parts
Clojure REPL: The Good Parts
 
"Simple Made Easy" Made Easy
"Simple Made Easy" Made Easy"Simple Made Easy" Made Easy
"Simple Made Easy" Made Easy
 
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
 
法学入門
法学入門法学入門
法学入門
 

Spectacular Future with clojure.spec