Successfully reported this slideshow.

Ekmett勉強会発表資料

21

Share

Upcoming SlideShare
Ekmett勉強会発表資料
Ekmett勉強会発表資料
Loading in …3
×
1 of 77
1 of 77

More Related Content

Related Audiobooks

Free with a 30 day trial from Scribd

See all

Ekmett勉強会発表資料

  1. 1. Lens で Haskell をもっと格好良く! for 2013/3/31 ekmett 勉強会 ちゅーん
  2. 2. 私はだあれ?  山手圏内で活動している 下っ端プログラマ  仕事の疲れは Haskell で癒す 日曜 Haskeller  Free モナドとか好きです  あと SDVX とか好き。音ゲーマーは Join me!
  3. 3. 本日のメニュー  Lens とは何か  Lens でタプルを便利にする  任意のデータ型を Lens で使う  Lens の仕組ってどーなってんの?  Lens の便利な関数紹介  まとめ的な何か ※ ゆるふわ注意
  4. 4. Lens とは何か
  5. 5. Lens とは・・・ タプルを始めとした任意のデータ構造の要素に対 する Setter や Getter を得るためのライブラリ Haskell で、 Java や C# といったオブジェクト指向 手続きプログラミングに似た記法で、要素にアクセ スできるようになる
  6. 6. Lens でタプルを便利にする
  7. 7. タプルの要素を取り出す方法  パターンマッチで取得する f (a, _, _) = a * 2  関数を定義して使う first (x, _, _) = x secound (_, x, _) = x third (_, _, x) = x g v = (first v) * 2
  8. 8. ネストした内側の要素を取り出す  パターンマッチするとなんかキモい 全パターン網羅するとか無理ぽ f ((_, (_, _, x)), _, _) = x  関数合成を使えば綺麗&簡単 third.snd.first $ ((1, (1, 1, 999)), 1, 1) -- => 999
  9. 9. 任意の位置の値を置き換えるには  パターンマッチを使って関数を書く。めんどい secondTo999 (x, _, y) = (x, 999, y)  関数を定義する setFirst x (_, a, b) = (x, a, b) setSecond x (a, _, b) = (a, x, b) setThird x (a, b, _) = (a, b, x) f'' = setSecond 999 (1, 2, 3) -- => (1,999,3)
  10. 10. ネストした内側の値を変更  素直に関数定義・・・超キモい f x ((a, (b, c, _)), d, e) = ((a, (b, c, x)), d, e)  関数合成ではできない ghci> :t setFirst.setThird setFirst.setThird :: a -> (t, t2, t3) -> ((t4, t5, t1) -> (t4, t5, a), t2, t3)  こうすればちょっとはマシ f x t = setThird (setFirst x $ third t) t
  11. 11. と に か く 超 不 満  値の取得と変更の識別子が異なる  タプルの要素数が異なると同じ識別子が使えない  構造がネストすると値の設定が超めんどい Java とか C# のような手続き言語で public 変数にアクセスするみたいに もっとスマートに構造を扱う事はできないの?
  12. 12. と に か く 超 不 満  値の取得と変更の識別子が異なる  タプルの要素数が異なると同じ識別子が使えない  構造がネストすると値の設定が超めんどい そこで Lens ですよ!! Java とか C# のような手続き言語で public 変数にアクセスするみたいに もっとスマートに構造を扱う事はできないの?
  13. 13. Lens のインストール  Cabal でいっぱつ $ cabal install lens  Hackage から直接アーカイブを取得 http://hackage.haskell.org/package/lens-3.9.0.2 コンパイルに時間がかかるので、 すごい H 本か TaPL あたりを読んでゆっくり待とう
  14. 14. Lens を import  Haskell のソースコードに Import Control.Lens  あるいは、 ghci で :m Contorol.Lens
  15. 15. Lens で要素の取得  (^.) と _1, _2, _3,... で簡単に取り出し ("Foo", "Bar", "Buz")^._1 -- => "Foo" ("Foo", "Bar", "Buz")^._2 -- => "Bar" ("Foo", "Bar", "Buz")^._3 -- => "Buz"  _1 ~ _9 まで別々の型クラスに定義されているので 要素数が異なるタプルに対しても同じように使える ('A', 'B', 'C', 'D', 'E')^._3 -- => 'C'
  16. 16. ネストしたタプルから要素を取り出す  _1 ~ _9 は (.) で関数合成しても同じ型 ghci> :t _1 _1 :: (Functor f, Field1 s t a b, Indexable Int p) => p a (f b) -> s -> f t ghci> :t _1._2 _1._2 :: (Functor f, Field2 s1 t1 a b, Field1 s t s1 t1, Indexable Int p) => p a (f b) -> s -> f t  _1 ~ _9 を (.) で合成して、ネストした 複雑なタプルの内側の値をピンポイントで取り出し (100, 200, (310, (321, 322, 323, 999, 325), 330), 400)^._3._2._4                                           -- => 999
  17. 17. Lens でタプルの値を変更  (.~) に _1 ~ _9 と、任意の値を適用 ghci> :t _2.~"Foo" _2.~"Foo" :: Field2 s t a [Char] => s -> t  要素が2つ以上のタプルは Field2 型クラス s のインスタンス ghci> :i Field2 class Field2 s t a b | s -> a, t -> b, s b -> t, t a -> s where _2 :: (Indexable Int p, Functor f) => p a (f b) -> s -> f t -- Defined in `Control.Lens.Tuple' ... -- Defined in `Control.Lens.Tuple' instance Field2 (a, b, c) (a, b', c) b b' -- Defined in `Control.Lens.Tuple' instance Field2 (a, b) (a, b') b b' -- Defined in `Control.Lens.Tuple'
  18. 18. Lens でタプルの値を変更  (.~) に _1 ~ _9 と、任意の値を適用 ghci> :t _2.~"Foo" _2.~"Foo" :: Field2 s t a [Char] => s -> t  _2.~”Foo” にタプルを適用すると 二つ目の要素が ” Foo” に変更される _2.~"Foo" $ (1, 2) -- => (1,"Foo") _2.~"Foo" $ (1, 2, 3) -- => (1,"Foo",3) _2.~"Foo" $ (1, 2, 3, 4) -- => (1,"Foo",3,4)
  19. 19. Lens でタプルの値を変更  勿論、 _1 ~ _9 を関数合成しても良い _4._2.~999 $ (1,2,3,(1,2,3),5) -- => (1,2,3,(1,999,3),5)  ($) の代わりに flip ($) と外延的等価な (&) を使う ghci> :i (&) (&) :: a -> (a -> b) -> b     -- Defined in `Control.Lens.Combinators' infixl 1 & (1,2,3,(1,2,3),5)&_4._2 .~ 999 -- => (1,2,3,(1,999,3),5)
  20. 20. Lens でタプルの値を変更  勿論、 _1 ~ _9 を関数合成しても良い _4._2.~999 $ (1,2,3,(1,2,3),5) -- => (1,2,3,(1,999,3),5)  ($) の代わりに flip ($) と外延的等価な (&) を使う Java や C# の代入文そっくり! ghci> :i (&) (&) :: a -> (a -> b) -> b     -- Defined in `Control.Lens.Combinators' infixl 1 & (1,2,3,(1,2,3),5)&_4._2 .~ 999 -- => (1,2,3,(1,999,3),5)
  21. 21. ここまでのまとめ タプルの操作には不満がまんまん でも Lens を使えば・・・  値の取得も変更も同じ識別子で参照できる  ネストしたタプルの値の変更も 手続き言語の代入感覚でらくらく書ける  それでいてしっかり型安全 ( これ重要) タプル以外の型もこんな風にできない?→
  22. 22. 任意のデータ型を Lens で使う
  23. 23. Point 型 /Line 型を作る  次のような型を作る data Point = Point { x :: Int, y :: Int } deriving (Show, Eq) data Line = Line { startPoint :: Point, endPoint :: Point } deriving (Show, Eq)  次の値を例に色々考えてみよう sampleLine = Line { startPoint = Point { x = 100, y = 150 }, endPoint = Point { x = 200, y = 250 } }
  24. 24. Point 単位の操作は簡単  取得 startPoint sampleLine -- => Point {x = 100, y = 150} endPoint sampleLine -- => Point {x = 200, y = 250}  置き換え SampleLine {    endPoint = Point { x = 1000, y = 1500 }}
  25. 25. では、座標単位の操作は?  取得は関数合成を使えば良い x . endPoint $ sampleLine -- => 200  置き換えは・・・いまいち分りづらい sampleLine { endPoint = (endPoint sampleLine) { x = 999 } } -- => Line { startPoint = Point {x = 100, y = 150}, endPoint = Point {x = 999, y = 250}}
  26. 26. では、座標単位の操作は?  取得は関数合成を使えば良い x . endPoint $ sampleLine -- => 200  置き換えは・・・いまいち分りづらい よし、 Lens を使おう! sampleLine { endPoint = (endPoint sampleLine) { x = 999 } } -- => Line { startPoint = Point {x = 100, y = 150}, endPoint = Point {x = 999, y = 250}}
  27. 27. Point 型 /Line 型を Lens にする  フィールド名の前に” _” を付加し 『 makeLenses '' 型名』 と記述する data Point = Point { _x :: Int, _y :: Int } deriving (Show, Eq) makeLenses ''Point data Line = Line { _startPoint :: Point, _endPoint :: Point } deriving (Show, Eq) makeLenses ''Line ※ コンパイルのためには GHC 拡張の TemplateHaskell を  有効にしておく必要がある
  28. 28. Point 型 /Line 型を Lens にする  フィールド名から” _” を抜いた識別子を使って (^.) や (.~) で要素にアクセスできるようになる sampleLine^.startPoint -- => Point {_x = 100, _y = 150} sampleLine^.endPoint -- => Point {_x = 200, _y = 250} sampleLine^.startPoint.x -- => 100 sampleLine^.endPoint.y -- => 250 sampleLine&startPoint.x.~999 -- => Line { -- _startPoint = Point {_x = 999, _y = 150}, -- _endPoint = Point {_x = 200, _y = 250}} sampleLine&endPoint.x.~999 -- => Line { -- _startPoint = Point {_x = 100, _y = 150}, -- _endPoint = Point {_x = 999, _y = 250}} カッコイイ!!
  29. 29. こんな場合はどうなる?  型変数が含まれる型でも data Foo a = Foo { _hoge :: a, _piyo :: Int } deriving (Show, Eq) makeLenses ''Foo sampleFoo = Foo { _hoge = "Hello!", _piyo = 100 }  もちろん大丈夫☆(ゝ ω ・) v sampleFoo^.hoge -- => "Hello!" sampleFoo^.piyo -- => 100 sampleFoo&hoge.~True -- => Foo {_hoge = True, _piyo = 100} sampleFoo&piyo.~999 -- => Foo {_hoge = "Hello!", _piyo = 999}
  30. 30. ここまでのまとめ 自分で作った型も Lens で操作したい! でも型とかややこしそうだし面倒では?  TemplateHaskell の力を借りて ちょ〜簡単に Lens になるよ  型変数を含む場合も無問題!  それでいてしっかり型安全 ( 大事なことなのでn (ry いったいどういう仕組みなんだろう?→
  31. 31. Lens の仕組ってどーなってんの?
  32. 32. Setter を作ろう  単純に 2 要素のタプルの 2 つめの要素を任意の 値に置き換える関数を考えると、次のような型にな る f :: a -> (b, c) -> (b, a)  これだけではつまらないので、一つ目の引数を関 数で取るようにする f :: (a -> b) -> (c, a) -> (c, b)
  33. 33. Setter を作ろう  単純に 2 要素のタプルの 2 つめの要素を任意の 値に置き換える関数を考えると、次のような型にな る f :: a -> (b, c) -> (b, a) 値を x に置き換えたい場合は  const x を適用すれば良い これだけではつまらないので、一つ目の引数を関 数で取るようにする f :: (a -> b) -> (c, a) -> (c, b)
  34. 34. ところで  この型、何かと似てない? f :: (a -> b) -> (c, a) -> (c, b) fmap :: Functor f => (a -> b) -> f a -> f b とそっくり・・・
  35. 35. ところで  この型、何かと似てない? f :: (a -> b) -> (c, a) -> (c, b) ※ 衆知のとおり、 2 値のタプルは Functor になっ ていて、次のような事ができる fmap (*2) ("Hey!", 5) -- => ("Hey!",10) しかし Functor では一つ目の要素は操作できない さて、どうしよう?
  36. 36. fmap のもうひとつの実装  Data.Traversable で定義されている Traversable 型クラスで、次の型を持つ traverse 関数が定義さ れている traverse :: Applicative f => (a -> f b) -> t a -> f (t b)  同モジュールの fmapDefault 関数は、 traverse 関 数を用いた fmap の別実装 fmapDefault :: Traversable t => (a -> b) -> t a -> t b fmapDefault f = getId . traverse (Id . f)
  37. 37. fmap のもうひとつの実装  Data.Traversable で定義されている Traversable 型クラスで、次の型を持つ traverse 関数が定義さ れているData.Functor.Identity の定義に同じ Id は newtype Id a = Id { getId :: a } traverse :: Applicative f => (a -> f b) -> t a -> f (t b) Functor と Applicative のインスンタンス  同モジュールの fmapDefault 関数は、 traverse 関 数を用いた fmap の別実装 fmapDefault :: Traversable t => (a -> b) -> t a -> t b fmapDefault f = getId . traverse (Id . f)
  38. 38. fmapDefault の 動作を決めるのは traverse 関数  なら、 traverse を別の関数と差し替えれば別の動 きをするんじゃなイカ?というわけで ... fmapDefault から traverse を外出しした over 関数 を定義すると、次のような型になる over :: ((a1 -> Id b) -> a -> Id c) -> (a1 -> b) -> a -> c over l f = getId . l (Id . f)  ここで、第一引数の型に対し Setter という別名を 付けよう type Setter s t a b = (a -> Id b) -> s -> Id t
  39. 39. fmapDefault の 動作を決めるのは traverse 関数  なら、 traverse を別の関数と差し替えれば別の動 きをするんじゃなイカ?というわけで ... fmapDefault から traverse を外出しした over 関数 を定義すると、次のような型になる over :: Setter a c a1 b -> (a1 -> b) -> a -> c over l f = getId . l (Id . f)  ここで、第一引数の型に対し Setter という別名を 付けよう type Setter s t a b = (a -> Id b) -> s -> Id t
  40. 40. fmapDefault の 動作を決めるのは traverse 関数  なら、 traverse を別の関数と差し替えれば別の動 きをするんじゃなイカ?というわけで ... これにより、 over の型がこう書ける fmapDefault から traverse を外出しした over 関数 を定義すると、次のような型になる over :: Setter a c a1 b -> (a1 -> b) -> a -> c over l f = getId . l (Id . f)  ここで、第一引数の型に対し Setter という別名を 付けよう type Setter s t a b = (a -> Id b) -> s -> Id t
  41. 41. fmapDefault の 動作を決めるのは traverse 関数  なら、 traverse を別の関数と差し替えれば別の動 きをするんじゃなイカ?というわけで ... fmapDefault から traverse を外出しした over 関数 を定義すると、次のような型になる over :: Setter a c a1 b -> (a1 -> b) -> a -> c over l f = getId . l (Id . f)  ここで、第一引数の型に対し Setter という別名を 付けよう type Setter s t a b = (a -> Id b) -> s -> Id t
  42. 42. fmapDefault の 動作を決めるのは traverse 関数  なら、 traverse を別の関数と差し替えれば別の動 きをするんじゃなイカ?というわけで ... fmapDefault から traverse を外出しした over 関数 を定義すると、次のような型になる over :: Setter a c a1 b -> (a1 -> b) -> a -> c over l f = getId . l (Id . f)  ここで、第一引数の型に対し Setter という別名を 当然、 traverse 関数を適用すれば 付けよう fmapDefault と同値になる さらに何かしら Setter 型の関数を引数に取る事により type Setter s t a b = (a -> Id b) -> s -> Id t fmap と似た別の関数を得る事ができる
  43. 43. _1, _2 を実装するには?  最終的に欲しい型 Over _1 :: (a -> b) -> (a, v) -> (b, v)  over の型を読み替え Over :: Setter (a, v) (b, v) a b -> (a -> b) -> (a, v) -> (b, v)  _1 の型 _1 :: Setter (a, v) (b, v) a b -- つまり _1 :: (a -> Id b) -> (a, v) -> Id (b, v)
  44. 44. 実際にやってみる  導きだした型を満足させるよう _1, _2 を実装 _1 :: Setter (a, v) (b, v) a b _1 f (x, y) = Id (getId . f $ x, y) _2 :: Setter (v, a) (v, b) a b _2 f (x, y) = Id (x, getId . f $ y)  任意の要素に fmap できるようになる! (over _1) (*2) (50, 50) -- => (100,50) (over _2) (*2) (50, 50) -- => (50,100)
  45. 45. こうなれば後は簡単  (.~) は次のようにして簡単に再実装できる (.~) :: Setter s t a b -> b -> s -> t a .~ v = over a (const v)  Lens と同じ書き方で要素を変更できるようになる _1.~999 $ (1, 2) => (999,2) _2.~999 $ (1, 2) => (1,999)
  46. 46. それじゃぁ次は Getter だ!  2 値のタプルからの値の取得は次のような型をイ メージできる f :: (a, b) -> b  単に取り出すだけでなく、何か関数を適用して返す ようにしてみると・・・ f :: (a -> b) -> (c, a) -> b  これは Data.Foldable で定義されている foldMap 関数とそっくり foldMap :: (Foldable t, Monoid m) => (a -> m) -> t a -> m
  47. 47. Traversable の foldMapDefault  FoldMapDefault の定義が Data.Traversable に! foldMapDefault :: (Traversable t, Monoid m) => (a -> m) -> t a -> m foldMapDefault f = getConst . traverse (Const . f) Const は Data.Functor.Constant に定義 newtype Const a b = Const {getConst :: a} Foldable や Applicative 等のインスンタンス
  48. 48. 同じようにして traverse を外に出す  foldMapDefault の実装から traverse を取り出し foldMapOf 関数を定義 foldMapOf :: ((a1 -> Const b1 b2) -> a -> Const c b) -> (a1 -> b1) -> a -> c foldMapOf l f = getConst . l (Const . f)  第一引数の関数の型に別名を付けてみる type Getting r s a = (a -> Const r a) -> s -> Const r s
  49. 49. アクセサの定義、 foldMapOf への適用  改めて、 2 値のタプルに対する _1, _2 を次のよう に定義 _1 :: Getting r (a, s) a _1 f (x, _) = Const (getConst . f $ x) _2 :: Getting r (s, a) a _2 f (_, y) = Const (getConst . f $ y)  foldMapOf と組み合わせて任意の場所の要素を foldMap (foldMapOf _1) (*2) (100, 1000) -- => 200 (foldMapOf _2) (*2) (100, 1000) -- => 2000
  50. 50. (^.) の実装も超簡単 (^.) :: s -> Getting a s a -> a v ^. l = (foldMapOf l) id v 値をそのまま取り出したいのだから 引数に対して何もしない関数 id :: a -> a を、適用してやれば良い (111, 222)^._1 -- => 111 (111, 222)^._2 -- => 222
  51. 51. Setter と Getting  どちらも traverse 関数を元に定義された型なのだ から、揃える事はできないだろうか? type Getting r s a = (a -> Const r a) -> s -> Const r s type Setter s t a b = (a -> Id b) -> s -> Id t  Getting の型変数を Setter に合わせて変えてみる type Getting s t a b = forall m .Monoid m => (a -> Const m b) -> s -> Const m t type Setter s t a b = (a -> Id b) -> s -> Id t
  52. 52. Setter と Getting  どちらも traverse 関数を元に定義された型なのだ から、揃える事はできないだろうか? type Getting r s a = 型定義に登場しない型変数 m (a -> Const r a) -> s -> Const r s type Setter s t a b = コンパイルのため、 FoldMap の実装に合せ (a -> Id b) -> s -> Id t Monoid を要求するようにしておく でもあまり嬉しくない制約  Getting の型変数を Setter に合わせて変えてみる type Getting s t a b = forall m .Monoid m => (a -> Const m b) -> s -> Const m t type Setter s t a b = (a -> Id b) -> s -> Id t
  53. 53. Id も Const も Functor !  従って、次の赤字の部分は、 Functor を要求する 型変数に置き換えることができる type Getting s t a b = forall m .Monoid m => (a -> Const m b) -> s -> Const m t type Setter s t a b = (a -> Id b) -> s -> Id t  これで型宣言も一つに纏められる しかも Getter の Monoid も消えた!やったね! type Lens s t a b = forall f .Functor f => (a -> f b) -> s -> f t
  54. 54. _1, _2 を作り替える  後は _1 と _2 を、それぞれ Lens 型に合うように実 装 _1 :: Lens (a, v) (b, v) a b _1 f (x, y) = fmap (x' -> (x', y)) (f x) _2 :: Lens (v, a) (v, b) a b _2 f (x, y) = fmap (y' -> (x, y')) (f y)  ちゃんと使えるかどうか確認・・・バッチリ! (100, 200)^._1 -- => 100 _1.~999 $ (100, 200) -- => (999,200)
  55. 55. traverse. traverse  traverse 関数同士を関数合成するとこうなる traverse :: (Control.Applicative.Applicative f, Traversable t) => (a -> f b) -> t a -> f (t b) traverse.traverse :: (Control.Applicative.Applicative f, Traversable t, Traversable t1) => (a -> f b) -> t (t1 a) -> f (t (t1 b)) traverse.traverse.traverse :: (Control.Applicative.Applicative f, Traversable t, Traversable t1, Traversable t2) => (a -> f b) -> t (t1 (t2 a)) -> f (t (t1 (t2 b))) 合成しても性質が維持される!
  56. 56. Lnes 型の関数は traverse と同じ型  なら _1 や _2 も同じ性質を持っているはず・・・ _2 :: Functor f => (a -> f b) -> (v, a) -> f (v, b) _2._2 :: Functor f => (a -> f b) -> (v, (v1, a)) -> f (v, (v1, b)) _2._2._2 :: Functor f => (a -> f b) -> (v, (v1, (v2, a))) -> f (v, (v1, (v2, b))) Lens が関数合成して使えるのは 型を見れば当然の事だった!!
  57. 57. そんなワケで  今回再実装したオレオレ Lens も _1 や _2 を関数合成して、ネストしたタプルの好き な要素にアクセスできるよっ _2._1.~"Lens" $ ("Hello", ((), "World")) -- => ("Hello",("Lens","World")) ("Hello", ("Lens", "World"))^._2._1 -- => "Lens"
  58. 58. (注)  今回の再実装で Id 、 Const という型を使ったが、 実際の Lens の実装では Mutator 、 Accessor と いう別実装を用いている これは、型エラーが発生した時に、よりエラーの原 因を特定しやすくするため。
  59. 59. ここまでのまとめ Lens の仕組みって凄い複雑そう・・・ 超人的な知能を持っていないと理解できない んじゃ?  Traversable 型クラスの fmapDefault 関 数 /foldMapDefault 関数から、型を中心に 追っていけば自然と導き出せるよ! もっと Lens の事が知りたいな!→
  60. 60. Lens の便利な関数紹介
  61. 61. と、その前に・・・  Control.Lens モジュール内では、 Lens と同じよう な型に様々な別名が付けられていて・・・ ・ Lens ・ Getter ・ Setter ・ Fold ・ Action ... 等々 それぞれ型クラスの制約なんかが少しづつ違って いたりするので、必要に応じて Hackage を参照
  62. 62. foldMapOf 関数 / over 関数  前の節で実装した foldMapOf 関数と over 関数は Lens モジュールをインポートしてそのまま使える (foldMapOf _2) (*100) (1, 2, 3) --=> 200 (over _2) (*100) (1, 2, 3) -- => (1,200,3) (foldMapOf y) (*2) $ Point { _x = 100, _y = 200 } -- => 400 (over x) (*2) $ Point { _x = 100, _y = 200 } -- => Point {_x = 200, _y = 200}  %~ は over の中置バージョン _2 %~ (*100) $ (1, 2, 3) -- => (1,200,3)
  63. 63. to 関数で関数適用  to 関数を使えば、 (^.) で取得した値に対して関数 適用できる (1, 2, 3)^._2.to (*100) -- => 200  さらに関数合成を連ねて次のようにしても良い (1,(10,20),3)^._2.to swap._2.to (*100)                          -- => 1000
  64. 64. Setter の演算子色々  対象となる要素が Num 型クラスのインスタンスや Bool 等の特定の型であれば、それらに対して便利 な演算子を使う事ができる。 -- 加算 (10, 20)&_1 +~ 100 -- => (110,20) -- 減算 (10, 20)&_1 -~ 5 -- => (5,20) -- 乗算 (10, 20)&_1 *~ 100 -- => (1000,20) -- 除算 (10, 20)&_1 //~ 5 -- => (2.0,20) --AND (True, 1)&_1 &&~ False -- => (False,1) --OR (True, 1)&_1 ||~ False -- => (True,1)
  65. 65. (.=) と use 関数  どちらも型クラス制約に MonadState クラスが含ま れている。 状態系のモナドと組み合わせて使う関数。 ghci> :t (.=) (.=) :: MonadState s m => ASetter s s a b -> b -> m () ghci> :t use use :: MonadState s m => Getting a s t a b -> m a
  66. 66. (.=) と use 関数  (.=) や use の簡単な例: sample :: State Line () sample = do -- (.=) で状態に代入 startPoint .= Point { _x = 100, _y = 200 } endPoint.x .= 300 -- 状態から値を取り出し sp <- use startPoint epx <- use $ endPoint.x return ()
  67. 67. 各 Setter 演算子の MonadState バージョン  何処かの言語で見たような書き方ができる sample2 = do v %= (*100) --over v += 10 -- 加算 v -= 10 -- 減算 v *= 10 -- 乗算 v //= 10 -- 除算 b ||= True --OR b &&= True --AND ※ 「状態」に対してかなりやりたい放題できるように なるので乱用注意!
  68. 68. Getter のアクセス時に モナドアクションを付加する Action  (^.) の代わりに (^!) を使うと、 act 関数を使ってモ ナドのアクセサにモナドアクションを追加する事が できる (("Foo", "Bar"), "Buz")^!_1.act (Just)._2 -- => Just "Bar" (("Lens", "Hello"), "World!")^!_1.act (x -> print x >> return x).to swap -- => ("Hello","Lens") ※ 途中で ("Lens","Hello") を print  次は Nothing になるかと思ったけど、 No instance エラーになった・・・ (´ ・ ω ・ `) ? (("Foo", "Bar"), "Buz")^!_1.act (const Nothing)._2
  69. 69. などなど  Lens モジュールには Lens をより便利に使う仕組 みが沢山用意されているので、 Hackage を一読し てみよう! http://hackage.haskell.org/package/lens-3.9.0.2
  70. 70. ところで・・・これは何だ・・・?  Lens の構成図を見る と、さらに下層に ISO とか Equality とか ゆー輩がいます…が Lens ISO Equality 勉強不足でご紹介で きないです orz ゴメンナサイ
  71. 71. まとめ的な何か
  72. 72. 改めて Lens って何?  レンズで覗くように複雑なデータ構造の内部に自在 にアクセスする手段を提供してくれるライブラリ軍  仕組みはやや複雑だけど Traversable を起点に 考えていけば考え方はとっても明瞭  単なるアクセサの域を超えた自在な操作を可能に するスーパーウルトラアルティメットアクセサ  もうちょっと秘められたパワーがありそうです
  73. 73. 大きいライブラリなので 尻込みしちゃうかもしれないけど Lens は全然怖くないよ!
  74. 74. !????
  75. 75. (((( ;゚ Д ゚ )))) こ・・・怖くねーし Lens 全然怖くねーから・・・
  76. 76. さぁ、みんな Lens を使おう! ご清聴ありがとうございました!!

×