SlideShare a Scribd company logo
1 of 85
Download to read offline
今から始める
Lens/Prism
2016/10/08 Scala関西Summit 2016
お前誰だよ?
Naoki Aoyama
アドテク系Scala エンジニア
コミッター
Twitter: , GitHub:
Monocle
@AoiroAoino @aoiroaoino
Lens/Prism ってご存知ですか?
Scala でLens/Prism を使うモチベーション
ネストした構造に対するcopy メソッドのネスト地獄
様々なデータを共通のインターフェースで操作できる
非侵入的に外側から追加できる
特定のアーキテクチャに依存しない概念
汎用的に使える
などなど
Lens って何?
getter/setter を抽象的にしたもの
purely functional reference
実は
余状態コモナド余代数
(Costate Comonad Coalgebra)
getter/setter ってなんだっけ?
(広く一般的な意味で)オブジェクト指向言語におい
て、あるfield の値を取得するメソッドがgetter で、 field
に値をセットするのがsetter。(広く一般的な意味で)
クラスのメソッドとして定義され、getFoo、setFoo と名
付けられる事が多い、おなじみの例のアレ。
getter/setter 再考
特定のclass に依存しない、汎用的な関数と捉えてみる
getter の仕事とは
オブジェクトからある値を取り出す
素直にシグネチャとして表してみると…
オブジェクトS からある値A を取り出す
S => A
// getter
def get[S, A]: S => A
setter の仕事とは
オブジェクトの一部をある値に変更する
素直にシグネチャとして表してみると…
オブジェクトS の一部をある値A に変更する
S => A => S
// setter
def set[S, A]: S => A => S
あるオブジェクトS の各field に対して前述のような
getter/setter が存在した時、 それらを使って汎用的な
get/set メソッドの提供を考える。
↓↓↓
その仕組みを実現するものをLens と呼ぶ。
get/set Lens
class Lens[S, A](
getter: S => A,
setter: S => A => S
) {
def get(s: S): A = getter(s)
def set(s: S, a: A): S = setter(s)(a)
def modify(s: S, f: A => A): S = set(s, f(get(s)))
}
get/set Lens
getter/setter をコンストラクタの引数として与える。
class Lens[S, A](
getter: S => A,
setter: S => A => S
) {
Lens の値を定義する
case class User(id: Int, name: String)
// User#id 対 Lens
val _id = new Lens[User, Int](
_.id, // getter
user => newId => user.copy(id = newId) // setter
)
// User#name 対 Lens
val _name = new Lens[User, String](
_.name, // getter
user => newName => user.copy(name = newName) // setter
)
使い方
val user1 = User(100, "John Doe")
_id.get(user1)
// res: Int = 100
_name.get(user1)
// res: String = John Doe
_name.set(user1, "Naoki Aoyama")
// res: User = User(100,Naoki Aoyama)
_name.modify(user1, _.toUpperCase)
// res: User = User(100,JOHN DOE)
Lens Laws
Lens には満たすべき法則がある。
get/set
set(s, get(s)) == s
set/get
get(set(s, a)) == a
set/set
set(set(s, a1), a2) == set(s, a2)
ネストしたデータが対象の時は?
ネストした構造に対するcopy メソッドのネスト地獄を
どう解決するか。
Lens の合成を考える
class Lens[S, A](getter: S => A, setter: S => A => S) {
def get(s: S): A = getter(s)
def set(s: S, a: A): S = setter(s)(a)
def modify(s: S, f: A => A): S = set(s, f(get(s)))
def ^|->[B](other: Lens[A, B]): Lens[S, B] = new Lens(
s => other.get(this.get(s)), // getter
s => b => this.set(s, other.set(this.get(s), b)) //setter
)
}
Lens の合成を考える
def ^|->[B](other: Lens[A, B]): Lens[S, B] = new Lens(
s => other.get(this.get(s)), // getter
s => b => this.set(s, other.set(this.get(s), b)) //setter
)
試してみよう
case class Message(user: User, body: String)
// Message#id 対 Lens
val _body = ...
// Message#user 対 Lens
val _user: Lens[Message, User] = new Lens(
_.user,
message => newUser => message.copy(user = newUser)
)
Before
val message = Message(User(100, "John Doe"), "Hello")
message.user // res: User = User(100,John Doe)
message.user.name // res: String = John Doe
message.copy(
user = user.copy(
name = "aoino"
)
) // res: Message = Message(User(100,aoino), Hello)
message.copy(
user = user.copy(
name = message.user.name.toUpperCase
)
) // res: Message = Message(User(100,JOHN DOE),Hello)
A er
val message = Message(User(100, "John Doe"), "Hello")
_user.get(message)
// res: User = User(100,John Doe)
(_user ^|-> _name).get(message)
// res: String = John Doe
(_user ^|-> _name).set(message, "aoino")
// res: Message = Message(User(100,aoino),Hello)
(_user ^|-> _name).modify(message, _.toUpperCase)
// res: Message = Message(User(100,JOHN DOE),Hello)
ところで
オブジェクトS にOption 型のfield が存在する場合に
get メソッドが適切に定義できるだろうか?
A == Option[B] となるようなLens を考えてみる。
class Lens[S, A](
getter: S => A,
setter: S => A => S
) {
// ...
}
すると、A がOption[B] となるような場合に
get メソッドが実装出来ない。
class BadLens[S, B](
getter: S => B,
setter: S => B => S
) {
def get(s: S): B = getter(s) match {
case Some(b) => b
case None => ??? /// 何 返
}
/// ...
}
ここで、Prism を導入する。
getter の取りうる引数に対して
setter が返すことが可能な値が足りない場合に
Lens だけではカバーしきれない。
↓↓↓
その仕組みを実現するものをPrism と呼ぶ。
Prism
class Prism[S, A](
_getOption: S => Option[A],
_reverseGet: A => S
) {
def getOption(s: S): Option[A] = _getOption(s)
def reverseGet(a: A): S = _reverseGet(a)
}
まずは、Some, None に対するPrism を定義する。
// Some 対 Prism
def _some[A] = new Prism[Option[A], A](
{ case Some(a) => Some(a); case None => None },
Some.apply
)
// None 対 Prism
def _none[A] = new Prism[Option[A], Unit](
{ case None => Some(()); case Some(_) => None },
_ => None
)
一部のユーザーにEmail アドレスの情報を
持たせたくなった場合を想定する。
case class User(id: Int, name: String, email: Option[String])
// User#email 対 Prism
val _email = new Lens[User, Option[String]](
_.email,
user => newEmail => user.copy(email = newEmail)
)
_some.getOption(_email.get(User(1, "aaa", Option("email"))))
// res: Option[String] = Some(email)
_some.getOption(_email.get(User(1, "aaa", None)))
// res: Option[String] = None
とてもダサい!!
_email.get, _some.getOption を直接呼び出している
コードの見通しが悪い
getOption の内部がより複雑だった場合
Lens の時と同じように合成を考えれば良い。
Q: Lens とPrism を合成すると何になる?
Lens
Prism
その他
A: Optional
Optics Hierarchie (Monocle)
ref. Monocle の よりREADME.md
Optics Hierarchie (lens)
ref. lens の よりREADME.md
Optional はLens とPrism の両方の性質を持つOptics
※ 下記コードはMonocle の よりOptional.scala
object Optional {
def apply[S, A](_getOption: S => Option[A])(_set: A => S => S): Optional
new Optional[S, A]{
// ...
}
}
Monocle を使って書くと以下の通り。
val user = User(1, "aaa", Some("email"))
(_email composePrism _some).getOption(user)
// res: String = email
様々な合成メソッドのエイリアスが
記号として提供されている。
(_email ^<-? _some).getOption(user)
// res: String = email
\( 'ω')/ウオオオオオアアアーーーッ!
^|->>
^|-?
^<-?
^|->
^<->
\(՞‫)◔ةڼ‬/ウオオオオオアアアーーーッ!?!?!?
ここまでのまとめ
Lens/Prism の概念と使い方を理解した
Optics Hierarchie を知った
Lens の種類
Lens にはコンセプトや実装に応じていくつか種類がある
get/set lens
get/modify lens
Iso lens
Store Comonad Lens
van Laarhoven lens
and so on ...
van Laarhoven Lens
van Laarhoven Lens とは?
2009 年7 月にTwan van Laarhoven さんが書いた の
アイディアが元になったLens で、Haskell の やScala
の のコンセプトの基礎になってる。
blog
lens
Monocle
def Lens[S, A, F[_]: Functor] = S => (A => F[A]) => F[S]
type Lens s a = forall f. Functor f => (a -> f a) -> s -> f s
閑話休題
traverse 関数はご存知ですか?
def traverse[G[_]: Applicative, A, B](fa: F[A])(f: A => G[B]): G[F[B]]
例えば、F をList、G をOption とすると、traverse 関数は
リスト内の値にf を適用し、全てSome だった場合には
f の適用結果をSome に包んで返し
一つでもNone の場合はNone を返します。
def isEven(v: Int): Option[Int] = if (v % 2 == 0) Some(v) else None
List(2, 4, 5).traverse(isEven)
// res: Option[List[Int]] = None
List(2, 4, 6).traverse(isEven)
// res: Option[List[Int]] = Some(List(2, 4, 6))
※ 上記コードはScalaz を使用しています。
閑話休題おわり
理解する為にgetter/setter を再考してみよう。
setter の再考
setter の再考
冒頭に出てきたsetter の型は以下の通り。
def setter: S => A => S
これはmodify メソッドの特殊形と考えられる。
なので、modify のsignature を取り入れて
def setter: S => (A => A) => S
と、改めて定義する。
この型に見覚えない?
trait Functor[F[_]] {
// F[A] => (A => B) => F[B]
def map[A, B](fa: F[A])(f: A => B): F[B]
}
つまり、我々はset/modify をするのに各field に対する
Functor#map が欲しいのだ。
しかし、Functor のinstance をclass のfield 毎にそれぞれ
定義することは現実的ではない...
Functor#map はTraverse#traverse で定義できる
trait Traverse[F[_]] extends Functor[F] {
// F[A] => (A => G[B]) => G[F[B]]
def traverse[G[_]: Applicative, A, B](fa: F[A])(f: A => G[B]): G[F[B
type Id[A] = A
// Id Applicative instance 自明
implicit def idApplicative[A] = new Applicative[Id] { ... }
// F[A] => (A => Id[B]) => Id[F[B]]
def map[A, B](fa: F[A])(f: A => B): F[B] =
traverse[Id, A, B](fa)(f)
}
つまり、このtraverse の部分を同等な関数に置き換える
ことで、Functor#map のような関数を得られる。この
F[A], F[B] をS と置いてSetter という名前をつけよう。
type Setter[S, A] = S => (A => Id[A]) => Id[S]
このSetter[S, A] を用いてset/modify メソッドが作れる。
// Setter[S, A] => S => (A => A) => S
def modify[S, A](setter: Setter[S, A])(s: S)(f: A => A): S =
setter(s)(a => (f(a): Id[A]))
// Setter[S, A] => S => A => S
def set[S, A](setter: Setter[S, A])(s: S)(a: A): S =
setter(s)(_ => (a: Id[A]))
動作確認
val _id: Setter[User, Int] =
(user: User) => (f: Int => Id[Int]) => user.copy(id = f(u.id))
scala> modify(_name)(User(100, "John Doe"))(_.toUpperCase)
// res: User = User(100,JOHN DOE)
scala> set(_name)(User(100, "John Doe"))("aoiroaoino")
// res: User = User(100,aoiroaoino)
\( 'ω')/ウオオオオオアアアーーーッ!
getter の再考
getter の再考
冒頭に出てきたgetter の型は以下の通り。
def getter: S => A
取得するだけでなく、関数を適用した結果を返すように
def getter: S => (A => A) => A
と、改めて定義する。
この型に見覚えない?
trait Foldable[F[_]] {
// F[A] => (A => B) => B
def foldMap[A, B](fa: F[A])(f: A => B)(implicit mb: Monoid[B]): B
}
つまり、我々はget をするのに各field に対する
Foldable#foldMap が欲しいのだ。
しかし、Foldable のinstance をclass のfield 毎にそれぞ
れ定義することは現実的ではない...
Foldable#foldMap はTraverse#traverse で定義できる
trait Traverse[F[_]] extends Functor[F] {
// F[A] => (A => G[B]) => G[F[B]]
def traverse[G[_]: Applicative, A, B](fa: F[A])(f: A => G[B]): G[F[B
// Const Applicative instance 自明
case class Const[A, B](runConst: A)
implicit def monoidApplicative[A](A: Monoid[A]) =
new Applicative[({type λ[X] = Const[A, X]})#λ] { ... }
// F[A] => (A => B) => B
def foldMap[A, B](fa: F[A])(f: A => B)(implicit mb: Monoid[B]): B =
traverse[({type λ[X] = Const[B, X]})#λ, A, Nothing](fa)(f)
}
Setter と同様にtraverse の部分を同等な関数に置き換え
ることで、Foldable#foldMap のような関数を得られる。
このF[A] をS と置いてGetter という名前をつけよう。
type Getting[R, S, A] = S => (A => Const[R, A]) => Const[R, S]
// S => (A => Const[A, A]) => Const[A, S]
type Getter[S, A] = Getting[A, S, A]
このGetter[S, A] を用いてget メソッドが作れる。
// Getter[S, A] => S => A
def get[S, A](getter: Getter[S, A])(s: S): A =
getter(s)(a => Const(a)).runConst
さて、我々は似たようなsignature を持つGetter/Setter を
手に入れた。これらを並べて見てみよう。
type Setter[S, A] = S => (A => Id[A]) => Id[S]
type Getter[S, A] = S => (A => Const[A, A]) => Const[A, S]
Const とId の部分をFunctor のinstance を要求する型変
数に置き換えられそう。
これでvan Laarhoven lens の定義を理解できましたね?
def Lens[S, A, F[_]: Functor] = S => (A => F[A]) => F[S]
type Lens s a = forall f. Functor f => (a -> f a) -> s -> f s
しかし、ここで一つ疑問が湧きませんか?
Q: van Laarhoven lens はうまく合成できるのだろうか?
Getter もSetter も中身はtraverse と同等の関数ですね。
なので、代表してtraverse の合成を見てみましょう。
f にId/Const が入ります。 構造のネストする順番と合成
の順序が一致し、左から右へと辿れますね。
traverse
:: (Applicative f, Traversable t) =>
(a -> f b) -> t a -> f (t b)
traverse . traverse
:: (Applicative f, Traversable t, Traversable t1) =>
(a -> f b) -> t (t1 a) -> f (t (t1 b))
traverse . traverse . traverse
:: (Applicative f, Traversable t, Traversable t1, Traversable t2) =>
(a -> f b) -> t (t1 (t2 a)) -> f (t (t1 (t2 b)))
おやおや?このHaskell の関数合成に使う(.) 演算子が、
Scala やJava などの(.) 演算子に見えませんか?
Haskell でvan Laarhoven Lens の合成はこう書ける。
ghci> set (_2 . _1) 42 ("hello",("world","!!!"))
("hello",(42,"!!!"))
A: Haskell だと超美しく合成できる...
まとめ
Lens/Prism の概念と使い方を完全マスターした
Optics Hierarchie と呼ばれる階層が存在する
Lens には種類がある
van Laarhoven lens はやばい

More Related Content

What's hot

SQL大量発行処理をいかにして高速化するか
SQL大量発行処理をいかにして高速化するかSQL大量発行処理をいかにして高速化するか
SQL大量発行処理をいかにして高速化するかShogo Wakayama
 
ゲーム開発者のための C++11/C++14
ゲーム開発者のための C++11/C++14ゲーム開発者のための C++11/C++14
ゲーム開発者のための C++11/C++14Ryo Suzuki
 
何となく勉強した気分になれるパーサ入門
何となく勉強した気分になれるパーサ入門何となく勉強した気分になれるパーサ入門
何となく勉強した気分になれるパーサ入門masayoshi takahashi
 
Pythonによる黒魔術入門
Pythonによる黒魔術入門Pythonによる黒魔術入門
Pythonによる黒魔術入門大樹 小倉
 
オンラインゲームの仕組みと工夫
オンラインゲームの仕組みと工夫オンラインゲームの仕組みと工夫
オンラインゲームの仕組みと工夫Yuta Imai
 
圏論のモナドとHaskellのモナド
圏論のモナドとHaskellのモナド圏論のモナドとHaskellのモナド
圏論のモナドとHaskellのモナドYoshihiro Mizoguchi
 
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」Takuto Wada
 
イミュータブルデータモデルの極意
イミュータブルデータモデルの極意イミュータブルデータモデルの極意
イミュータブルデータモデルの極意Yoshitaka Kawashima
 
目grep入門 +解説
目grep入門 +解説目grep入門 +解説
目grep入門 +解説murachue
 
20分くらいでわかった気分になれるC++20コルーチン
20分くらいでわかった気分になれるC++20コルーチン20分くらいでわかった気分になれるC++20コルーチン
20分くらいでわかった気分になれるC++20コルーチンyohhoy
 
TRICK 2022 Results
TRICK 2022 ResultsTRICK 2022 Results
TRICK 2022 Resultsmametter
 
イベント駆動プログラミングとI/O多重化
イベント駆動プログラミングとI/O多重化イベント駆動プログラミングとI/O多重化
イベント駆動プログラミングとI/O多重化Gosuke Miyashita
 
できる!並列・並行プログラミング
できる!並列・並行プログラミングできる!並列・並行プログラミング
できる!並列・並行プログラミングPreferred Networks
 
高速な倍精度指数関数expの実装
高速な倍精度指数関数expの実装高速な倍精度指数関数expの実装
高速な倍精度指数関数expの実装MITSUNARI Shigeo
 
1076: CUDAデバッグ・プロファイリング入門
1076: CUDAデバッグ・プロファイリング入門1076: CUDAデバッグ・プロファイリング入門
1076: CUDAデバッグ・プロファイリング入門NVIDIA Japan
 
メルカリ・ソウゾウでは どうGoを活用しているのか?
メルカリ・ソウゾウでは どうGoを活用しているのか?メルカリ・ソウゾウでは どうGoを活用しているのか?
メルカリ・ソウゾウでは どうGoを活用しているのか?Takuya Ueda
 
Scalaで型クラス入門
Scalaで型クラス入門Scalaで型クラス入門
Scalaで型クラス入門Makoto Fukuhara
 

What's hot (20)

SQL大量発行処理をいかにして高速化するか
SQL大量発行処理をいかにして高速化するかSQL大量発行処理をいかにして高速化するか
SQL大量発行処理をいかにして高速化するか
 
ゲーム開発者のための C++11/C++14
ゲーム開発者のための C++11/C++14ゲーム開発者のための C++11/C++14
ゲーム開発者のための C++11/C++14
 
何となく勉強した気分になれるパーサ入門
何となく勉強した気分になれるパーサ入門何となく勉強した気分になれるパーサ入門
何となく勉強した気分になれるパーサ入門
 
Pythonによる黒魔術入門
Pythonによる黒魔術入門Pythonによる黒魔術入門
Pythonによる黒魔術入門
 
オンラインゲームの仕組みと工夫
オンラインゲームの仕組みと工夫オンラインゲームの仕組みと工夫
オンラインゲームの仕組みと工夫
 
圏論のモナドとHaskellのモナド
圏論のモナドとHaskellのモナド圏論のモナドとHaskellのモナド
圏論のモナドとHaskellのモナド
 
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
 
イミュータブルデータモデルの極意
イミュータブルデータモデルの極意イミュータブルデータモデルの極意
イミュータブルデータモデルの極意
 
目grep入門 +解説
目grep入門 +解説目grep入門 +解説
目grep入門 +解説
 
20分くらいでわかった気分になれるC++20コルーチン
20分くらいでわかった気分になれるC++20コルーチン20分くらいでわかった気分になれるC++20コルーチン
20分くらいでわかった気分になれるC++20コルーチン
 
TRICK 2022 Results
TRICK 2022 ResultsTRICK 2022 Results
TRICK 2022 Results
 
イベント駆動プログラミングとI/O多重化
イベント駆動プログラミングとI/O多重化イベント駆動プログラミングとI/O多重化
イベント駆動プログラミングとI/O多重化
 
できる!並列・並行プログラミング
できる!並列・並行プログラミングできる!並列・並行プログラミング
できる!並列・並行プログラミング
 
高速な倍精度指数関数expの実装
高速な倍精度指数関数expの実装高速な倍精度指数関数expの実装
高速な倍精度指数関数expの実装
 
1076: CUDAデバッグ・プロファイリング入門
1076: CUDAデバッグ・プロファイリング入門1076: CUDAデバッグ・プロファイリング入門
1076: CUDAデバッグ・プロファイリング入門
 
メルカリ・ソウゾウでは どうGoを活用しているのか?
メルカリ・ソウゾウでは どうGoを活用しているのか?メルカリ・ソウゾウでは どうGoを活用しているのか?
メルカリ・ソウゾウでは どうGoを活用しているのか?
 
Map
MapMap
Map
 
Scalaで型クラス入門
Scalaで型クラス入門Scalaで型クラス入門
Scalaで型クラス入門
 
Glibc malloc internal
Glibc malloc internalGlibc malloc internal
Glibc malloc internal
 
明日使えないすごいビット演算
明日使えないすごいビット演算明日使えないすごいビット演算
明日使えないすごいビット演算
 

Similar to 今から始める Lens/Prism

Van laarhoven lens
Van laarhoven lensVan laarhoven lens
Van laarhoven lensNaoki Aoyama
 
Ekmett勉強会発表資料
Ekmett勉強会発表資料Ekmett勉強会発表資料
Ekmett勉強会発表資料時響 逢坂
 
Go言語のスライスを理解しよう
Go言語のスライスを理解しようGo言語のスライスを理解しよう
Go言語のスライスを理解しようYasutaka Kawamoto
 
Essential Scala 第5章 シーケンス処理
Essential Scala 第5章 シーケンス処理Essential Scala 第5章 シーケンス処理
Essential Scala 第5章 シーケンス処理Takuya Tsuchida
 
【C++BUILDER STARTER チュートリアルシリーズ】シーズン2 C++Builderの部 第5回 ‟配列と構造体„
【C++BUILDER STARTER チュートリアルシリーズ】シーズン2 C++Builderの部 第5回 ‟配列と構造体„【C++BUILDER STARTER チュートリアルシリーズ】シーズン2 C++Builderの部 第5回 ‟配列と構造体„
【C++BUILDER STARTER チュートリアルシリーズ】シーズン2 C++Builderの部 第5回 ‟配列と構造体„和弘 井之上
 
復習も兼ねて!C#6.0-7.0
復習も兼ねて!C#6.0-7.0復習も兼ねて!C#6.0-7.0
復習も兼ねて!C#6.0-7.0Yuta Matsumura
 
eZ Publish勉強会9月〜テンプレート言語〜
eZ Publish勉強会9月〜テンプレート言語〜eZ Publish勉強会9月〜テンプレート言語〜
eZ Publish勉強会9月〜テンプレート言語〜ericsagnes
 
AuxパターンをDottyで解決する
AuxパターンをDottyで解決するAuxパターンをDottyで解決する
AuxパターンをDottyで解決するTaisuke Oe
 
現実世界のJRuby(ショートバージョン)
現実世界のJRuby(ショートバージョン)現実世界のJRuby(ショートバージョン)
現実世界のJRuby(ショートバージョン)Hiroshi Nakamura
 
What Dotty fixes @ Scala関西サミット
What Dotty fixes @ Scala関西サミットWhat Dotty fixes @ Scala関西サミット
What Dotty fixes @ Scala関西サミットTaisuke Oe
 
関数モデル 【クラウドアプリケーションのためのオブジェクト指向分析設計講座 第8回】
関数モデル 【クラウドアプリケーションのためのオブジェクト指向分析設計講座 第8回】関数モデル 【クラウドアプリケーションのためのオブジェクト指向分析設計講座 第8回】
関数モデル 【クラウドアプリケーションのためのオブジェクト指向分析設計講座 第8回】Tomoharu ASAMI
 
Flutterを体験してみませんか
Flutterを体験してみませんかFlutterを体験してみませんか
Flutterを体験してみませんかcch-robo
 
Ekmett勉強会発表資料
Ekmett勉強会発表資料Ekmett勉強会発表資料
Ekmett勉強会発表資料時響 逢坂
 
C++ Template Meta Programming の紹介@社内勉強会
C++ Template Meta Programming の紹介@社内勉強会C++ Template Meta Programming の紹介@社内勉強会
C++ Template Meta Programming の紹介@社内勉強会Akihiko Matuura
 
TypeScript & 関数型講座 第2回 TypeScript という言語
TypeScript & 関数型講座 第2回 TypeScript という言語TypeScript & 関数型講座 第2回 TypeScript という言語
TypeScript & 関数型講座 第2回 TypeScript という言語gypsygypsy
 
Python standard 2022 Spring
Python standard 2022 SpringPython standard 2022 Spring
Python standard 2022 Springanyakichi
 

Similar to 今から始める Lens/Prism (20)

Van laarhoven lens
Van laarhoven lensVan laarhoven lens
Van laarhoven lens
 
MP in Scala
MP in ScalaMP in Scala
MP in Scala
 
Ekmett勉強会発表資料
Ekmett勉強会発表資料Ekmett勉強会発表資料
Ekmett勉強会発表資料
 
Go言語のスライスを理解しよう
Go言語のスライスを理解しようGo言語のスライスを理解しよう
Go言語のスライスを理解しよう
 
Essential Scala 第5章 シーケンス処理
Essential Scala 第5章 シーケンス処理Essential Scala 第5章 シーケンス処理
Essential Scala 第5章 シーケンス処理
 
【C++BUILDER STARTER チュートリアルシリーズ】シーズン2 C++Builderの部 第5回 ‟配列と構造体„
【C++BUILDER STARTER チュートリアルシリーズ】シーズン2 C++Builderの部 第5回 ‟配列と構造体„【C++BUILDER STARTER チュートリアルシリーズ】シーズン2 C++Builderの部 第5回 ‟配列と構造体„
【C++BUILDER STARTER チュートリアルシリーズ】シーズン2 C++Builderの部 第5回 ‟配列と構造体„
 
復習も兼ねて!C#6.0-7.0
復習も兼ねて!C#6.0-7.0復習も兼ねて!C#6.0-7.0
復習も兼ねて!C#6.0-7.0
 
Scala on Hadoop
Scala on HadoopScala on Hadoop
Scala on Hadoop
 
現実世界のJRuby
現実世界のJRuby現実世界のJRuby
現実世界のJRuby
 
eZ Publish勉強会9月〜テンプレート言語〜
eZ Publish勉強会9月〜テンプレート言語〜eZ Publish勉強会9月〜テンプレート言語〜
eZ Publish勉強会9月〜テンプレート言語〜
 
AuxパターンをDottyで解決する
AuxパターンをDottyで解決するAuxパターンをDottyで解決する
AuxパターンをDottyで解決する
 
現実世界のJRuby(ショートバージョン)
現実世界のJRuby(ショートバージョン)現実世界のJRuby(ショートバージョン)
現実世界のJRuby(ショートバージョン)
 
Pfi Seminar 2010 1 7
Pfi Seminar 2010 1 7Pfi Seminar 2010 1 7
Pfi Seminar 2010 1 7
 
What Dotty fixes @ Scala関西サミット
What Dotty fixes @ Scala関西サミットWhat Dotty fixes @ Scala関西サミット
What Dotty fixes @ Scala関西サミット
 
関数モデル 【クラウドアプリケーションのためのオブジェクト指向分析設計講座 第8回】
関数モデル 【クラウドアプリケーションのためのオブジェクト指向分析設計講座 第8回】関数モデル 【クラウドアプリケーションのためのオブジェクト指向分析設計講座 第8回】
関数モデル 【クラウドアプリケーションのためのオブジェクト指向分析設計講座 第8回】
 
Flutterを体験してみませんか
Flutterを体験してみませんかFlutterを体験してみませんか
Flutterを体験してみませんか
 
Ekmett勉強会発表資料
Ekmett勉強会発表資料Ekmett勉強会発表資料
Ekmett勉強会発表資料
 
C++ Template Meta Programming の紹介@社内勉強会
C++ Template Meta Programming の紹介@社内勉強会C++ Template Meta Programming の紹介@社内勉強会
C++ Template Meta Programming の紹介@社内勉強会
 
TypeScript & 関数型講座 第2回 TypeScript という言語
TypeScript & 関数型講座 第2回 TypeScript という言語TypeScript & 関数型講座 第2回 TypeScript という言語
TypeScript & 関数型講座 第2回 TypeScript という言語
 
Python standard 2022 Spring
Python standard 2022 SpringPython standard 2022 Spring
Python standard 2022 Spring
 

今から始める Lens/Prism