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

コンテナの作り方「Dockerは裏方で何をしているのか?」
コンテナの作り方「Dockerは裏方で何をしているのか?」コンテナの作り方「Dockerは裏方で何をしているのか?」
コンテナの作り方「Dockerは裏方で何をしているのか?」Masahito Zembutsu
 
Pythonによる黒魔術入門
Pythonによる黒魔術入門Pythonによる黒魔術入門
Pythonによる黒魔術入門大樹 小倉
 
きつねさんでもわかるLlvm読書会 第2回
きつねさんでもわかるLlvm読書会 第2回きつねさんでもわかるLlvm読書会 第2回
きつねさんでもわかるLlvm読書会 第2回Tomoya Kawanishi
 
SPAセキュリティ入門~PHP Conference Japan 2021
SPAセキュリティ入門~PHP Conference Japan 2021SPAセキュリティ入門~PHP Conference Japan 2021
SPAセキュリティ入門~PHP Conference Japan 2021Hiroshi Tokumaru
 
Python 3.9からの新定番zoneinfoを使いこなそう
Python 3.9からの新定番zoneinfoを使いこなそうPython 3.9からの新定番zoneinfoを使いこなそう
Python 3.9からの新定番zoneinfoを使いこなそうRyuji Tsutsui
 
高速な倍精度指数関数expの実装
高速な倍精度指数関数expの実装高速な倍精度指数関数expの実装
高速な倍精度指数関数expの実装MITSUNARI Shigeo
 
【Unite Tokyo 2019】Understanding C# Struct All Things
【Unite Tokyo 2019】Understanding C# Struct All Things【Unite Tokyo 2019】Understanding C# Struct All Things
【Unite Tokyo 2019】Understanding C# Struct All ThingsUnityTechnologiesJapan002
 
入門 Kubeflow ~Kubernetesで機械学習をはじめるために~ (NTT Tech Conference #4 講演資料)
入門 Kubeflow ~Kubernetesで機械学習をはじめるために~ (NTT Tech Conference #4 講演資料)入門 Kubeflow ~Kubernetesで機械学習をはじめるために~ (NTT Tech Conference #4 講演資料)
入門 Kubeflow ~Kubernetesで機械学習をはじめるために~ (NTT Tech Conference #4 講演資料)NTT DATA Technology & Innovation
 
constexpr関数はコンパイル時処理。これはいい。実行時が霞んで見える。cpuの嬌声が聞こえてきそうだ
constexpr関数はコンパイル時処理。これはいい。実行時が霞んで見える。cpuの嬌声が聞こえてきそうだconstexpr関数はコンパイル時処理。これはいい。実行時が霞んで見える。cpuの嬌声が聞こえてきそうだ
constexpr関数はコンパイル時処理。これはいい。実行時が霞んで見える。cpuの嬌声が聞こえてきそうだGenya Murakami
 
こわくない Git
こわくない Gitこわくない Git
こわくない GitKota Saito
 
ドメイン駆動設計 ( DDD ) をやってみよう
ドメイン駆動設計 ( DDD ) をやってみようドメイン駆動設計 ( DDD ) をやってみよう
ドメイン駆動設計 ( DDD ) をやってみよう増田 亨
 
.NET Core 3.0時代のメモリ管理
.NET Core 3.0時代のメモリ管理.NET Core 3.0時代のメモリ管理
.NET Core 3.0時代のメモリ管理KageShiron
 
Redisの特徴と活用方法について
Redisの特徴と活用方法についてRedisの特徴と活用方法について
Redisの特徴と活用方法についてYuji Otani
 
乗っ取れコンテナ!!開発者から見たコンテナセキュリティの考え方(CloudNative Days Tokyo 2021 発表資料)
乗っ取れコンテナ!!開発者から見たコンテナセキュリティの考え方(CloudNative Days Tokyo 2021 発表資料)乗っ取れコンテナ!!開発者から見たコンテナセキュリティの考え方(CloudNative Days Tokyo 2021 発表資料)
乗っ取れコンテナ!!開発者から見たコンテナセキュリティの考え方(CloudNative Days Tokyo 2021 発表資料)NTT DATA Technology & Innovation
 
マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!mosa siru
 
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」Takuto Wada
 
良い?悪い?コードコメントの書き方
良い?悪い?コードコメントの書き方良い?悪い?コードコメントの書き方
良い?悪い?コードコメントの書き方Shigenori Sagawa
 

What's hot (20)

コンテナの作り方「Dockerは裏方で何をしているのか?」
コンテナの作り方「Dockerは裏方で何をしているのか?」コンテナの作り方「Dockerは裏方で何をしているのか?」
コンテナの作り方「Dockerは裏方で何をしているのか?」
 
Pythonによる黒魔術入門
Pythonによる黒魔術入門Pythonによる黒魔術入門
Pythonによる黒魔術入門
 
きつねさんでもわかるLlvm読書会 第2回
きつねさんでもわかるLlvm読書会 第2回きつねさんでもわかるLlvm読書会 第2回
きつねさんでもわかるLlvm読書会 第2回
 
SPAセキュリティ入門~PHP Conference Japan 2021
SPAセキュリティ入門~PHP Conference Japan 2021SPAセキュリティ入門~PHP Conference Japan 2021
SPAセキュリティ入門~PHP Conference Japan 2021
 
Python 3.9からの新定番zoneinfoを使いこなそう
Python 3.9からの新定番zoneinfoを使いこなそうPython 3.9からの新定番zoneinfoを使いこなそう
Python 3.9からの新定番zoneinfoを使いこなそう
 
高速な倍精度指数関数expの実装
高速な倍精度指数関数expの実装高速な倍精度指数関数expの実装
高速な倍精度指数関数expの実装
 
【Unite Tokyo 2019】Understanding C# Struct All Things
【Unite Tokyo 2019】Understanding C# Struct All Things【Unite Tokyo 2019】Understanding C# Struct All Things
【Unite Tokyo 2019】Understanding C# Struct All Things
 
入門 Kubeflow ~Kubernetesで機械学習をはじめるために~ (NTT Tech Conference #4 講演資料)
入門 Kubeflow ~Kubernetesで機械学習をはじめるために~ (NTT Tech Conference #4 講演資料)入門 Kubeflow ~Kubernetesで機械学習をはじめるために~ (NTT Tech Conference #4 講演資料)
入門 Kubeflow ~Kubernetesで機械学習をはじめるために~ (NTT Tech Conference #4 講演資料)
 
constexpr関数はコンパイル時処理。これはいい。実行時が霞んで見える。cpuの嬌声が聞こえてきそうだ
constexpr関数はコンパイル時処理。これはいい。実行時が霞んで見える。cpuの嬌声が聞こえてきそうだconstexpr関数はコンパイル時処理。これはいい。実行時が霞んで見える。cpuの嬌声が聞こえてきそうだ
constexpr関数はコンパイル時処理。これはいい。実行時が霞んで見える。cpuの嬌声が聞こえてきそうだ
 
こわくない Git
こわくない Gitこわくない Git
こわくない Git
 
ドメイン駆動設計 ( DDD ) をやってみよう
ドメイン駆動設計 ( DDD ) をやってみようドメイン駆動設計 ( DDD ) をやってみよう
ドメイン駆動設計 ( DDD ) をやってみよう
 
.NET Core 3.0時代のメモリ管理
.NET Core 3.0時代のメモリ管理.NET Core 3.0時代のメモリ管理
.NET Core 3.0時代のメモリ管理
 
Docker Compose 徹底解説
Docker Compose 徹底解説Docker Compose 徹底解説
Docker Compose 徹底解説
 
Map
MapMap
Map
 
Redisの特徴と活用方法について
Redisの特徴と活用方法についてRedisの特徴と活用方法について
Redisの特徴と活用方法について
 
乗っ取れコンテナ!!開発者から見たコンテナセキュリティの考え方(CloudNative Days Tokyo 2021 発表資料)
乗っ取れコンテナ!!開発者から見たコンテナセキュリティの考え方(CloudNative Days Tokyo 2021 発表資料)乗っ取れコンテナ!!開発者から見たコンテナセキュリティの考え方(CloudNative Days Tokyo 2021 発表資料)
乗っ取れコンテナ!!開発者から見たコンテナセキュリティの考え方(CloudNative Days Tokyo 2021 発表資料)
 
マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!
 
Kotlinアンチパターン
KotlinアンチパターンKotlinアンチパターン
Kotlinアンチパターン
 
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
 
良い?悪い?コードコメントの書き方
良い?悪い?コードコメントの書き方良い?悪い?コードコメントの書き方
良い?悪い?コードコメントの書き方
 

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