SlideShare a Scribd company logo
Lens で Haskell をもっと格好良く!




          for 2013/3/31 ekmett 勉強会
                          ちゅーん
私はだあれ?

   山手圏内で活動している
    下っ端プログラマ
   仕事の疲れは Haskell で癒す
    日曜 Haskeller
   Free モナドとか好きです



   あと SDVX とか好き。音ゲーマーは Join me!
本日のメニュー

   Lens とは何か
   Lens でタプルを便利にする
   任意のデータ型を Lens で使う
   Lens の仕組ってどーなってんの?
   Lens の便利な関数紹介
   まとめ的な何か


                        ※ ゆるふわ注意
Lens とは何か
Lens とは・・・



 タプルを始めとした任意のデータ構造の要素に対
 する Setter や Getter を得るためのライブラリ
 Haskell で、 Java や C# といったオブジェクト指向
 手続きプログラミングに似た記法で、要素にアクセ
 スできるようになる
Lens でタプルを便利にする
タプルの要素を取り出す方法

   パターンマッチで取得する

    f (a, _, _) = a * 2

   関数を定義して使う

    first   (x, _, _) = x
    secound (_, x, _) = x
    third   (_, _, x) = x

    g v = (first v) * 2
ネストした内側の要素を取り出す

   パターンマッチするとなんかキモい
    全パターン網羅するとか無理ぽ

    f ((_, (_, _, x)), _, _) = x


   関数合成を使えば綺麗&簡単
    third.snd.first $ ((1, (1, 1, 999)), 1, 1)
                                        -- => 999
任意の位置の値を置き換えるには

   パターンマッチを使って関数を書く。めんどい

    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)
ネストした内側の値を変更
   素直に関数定義・・・超キモい
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
と に か く 超 不 満

   値の取得と変更の識別子が異なる
   タプルの要素数が異なると同じ識別子が使えない
   構造がネストすると値の設定が超めんどい


    Java とか C# のような手続き言語で
    public 変数にアクセスするみたいに
    もっとスマートに構造を扱う事はできないの?
と に か く 超 不 満

   値の取得と変更の識別子が異なる
   タプルの要素数が異なると同じ識別子が使えない
   構造がネストすると値の設定が超めんどい

       そこで Lens ですよ!!
    Java とか C# のような手続き言語で
    public 変数にアクセスするみたいに
    もっとスマートに構造を扱う事はできないの?
Lens のインストール
   Cabal でいっぱつ

$ cabal install lens


   Hackage から直接アーカイブを取得


    http://hackage.haskell.org/package/lens-3.9.0.2


    コンパイルに時間がかかるので、
    すごい H 本か TaPL あたりを読んでゆっくり待とう
Lens を import

   Haskell のソースコードに

Import Control.Lens



   あるいは、 ghci で

:m Contorol.Lens
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'
ネストしたタプルから要素を取り出す
    _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
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'
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)
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)
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)
ここまでのまとめ

    タプルの操作には不満がまんまん
    でも Lens を使えば・・・
   値の取得も変更も同じ識別子で参照できる
   ネストしたタプルの値の変更も
    手続き言語の代入感覚でらくらく書ける

    それでいてしっかり型安全 ( これ重要)

      タプル以外の型もこんな風にできない?→
任意のデータ型を Lens で使う
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 }
      }
Point 単位の操作は簡単

   取得
    startPoint sampleLine
       -- => Point {x = 100, y = 150}
    endPoint sampleLine
       -- => Point {x = 200, y = 250}

   置き換え

    SampleLine {
       endPoint = Point { x = 1000, y = 1500 }}
では、座標単位の操作は?

    取得は関数合成を使えば良い

      x . endPoint $ sampleLine -- => 200

    置き換えは・・・いまいち分りづらい

    sampleLine {
      endPoint = (endPoint sampleLine) { x = 999 } }

      -- => Line {
              startPoint = Point {x = 100, y = 150},
              endPoint   = Point {x = 999, y = 250}}
では、座標単位の操作は?

    取得は関数合成を使えば良い

      x . endPoint $ sampleLine -- => 200

    置き換えは・・・いまいち分りづらい
            よし、 Lens を使おう!
    sampleLine {
      endPoint = (endPoint sampleLine) { x = 999 } }

      -- => Line {
              startPoint = Point {x = 100, y = 150},
              endPoint   = Point {x = 999, y = 250}}
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 を
     有効にしておく必要がある
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}}


                           カッコイイ!!
こんな場合はどうなる?
   型変数が含まれる型でも
    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}
ここまでのまとめ
    自分で作った型も Lens で操作したい!
    でも型とかややこしそうだし面倒では?
   TemplateHaskell の力を借りて
    ちょ〜簡単に Lens になるよ
   型変数を含む場合も無問題!

    それでいてしっかり型安全 ( 大事なことなのでn (ry


        いったいどういう仕組みなんだろう?→
Lens の仕組ってどーなってんの?
Setter を作ろう

   単純に 2 要素のタプルの 2 つめの要素を任意の
    値に置き換える関数を考えると、次のような型にな
    る

       f :: a -> (b, c) -> (b, a)

   これだけではつまらないので、一つ目の引数を関
    数で取るようにする

    f :: (a -> b) -> (c, a) -> (c, b)
Setter を作ろう

   単純に 2 要素のタプルの 2 つめの要素を任意の
    値に置き換える関数を考えると、次のような型にな
    る

       f :: a -> (b, c) -> (b, a)
         値を x に置き換えたい場合は
         const x を適用すれば良い
    これだけではつまらないので、一つ目の引数を関
    数で取るようにする

    f :: (a -> b) -> (c, a) -> (c, b)
ところで

   この型、何かと似てない?

    f :: (a -> b) -> (c, a) -> (c, b)



      fmap :: Functor f => (a -> b) -> f a -> f b
                   とそっくり・・・
ところで

   この型、何かと似てない?

     f :: (a -> b) -> (c, a) -> (c, b)

    ※ 衆知のとおり、 2 値のタプルは Functor になっ
    ていて、次のような事ができる

    fmap (*2) ("Hey!", 5) -- => ("Hey!",10)

    しかし Functor では一つ目の要素は操作できない
    さて、どうしよう?
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)
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)
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
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
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
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
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 と似た別の関数を得る事ができる
_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)
実際にやってみる
    導きだした型を満足させるよう _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)
こうなれば後は簡単

    (.~) は次のようにして簡単に再実装できる

    (.~) :: 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)
それじゃぁ次は 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
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 等のインスンタンス
同じようにして 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
アクセサの定義、
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
(^.) の実装も超簡単

(^.) :: s -> Getting a s a -> a
v ^. l = (foldMapOf l) id v

           値をそのまま取り出したいのだから
          引数に対して何もしない関数 id :: a -> a
              を、適用してやれば良い



(111, 222)^._1 -- => 111
(111, 222)^._2 -- => 222
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
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
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
_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)
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)))

    合成しても性質が維持される!
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 が関数合成して使えるのは
     型を見れば当然の事だった!!
そんなワケで

    今回再実装したオレオレ Lens も
     _1 や _2 を関数合成して、ネストしたタプルの好き
     な要素にアクセスできるよっ


    _2._1.~"Lens" $ ("Hello", ((), "World"))
                            -- => ("Hello",("Lens","World"))

    ("Hello", ("Lens", "World"))^._2._1
                            -- => "Lens"
(注)

   今回の再実装で Id 、 Const という型を使ったが、
    実際の Lens の実装では Mutator 、 Accessor と
    いう別実装を用いている


    これは、型エラーが発生した時に、よりエラーの原
    因を特定しやすくするため。
ここまでのまとめ
    Lens の仕組みって凄い複雑そう・・・
    超人的な知能を持っていないと理解できない
    んじゃ?
   Traversable 型クラスの fmapDefault 関
    数 /foldMapDefault 関数から、型を中心に
    追っていけば自然と導き出せるよ!



           もっと Lens の事が知りたいな!→
Lens の便利な関数紹介
と、その前に・・・
   Control.Lens モジュール内では、 Lens と同じよう
    な型に様々な別名が付けられていて・・・
    ・ Lens
    ・ Getter
    ・ Setter
    ・ Fold
    ・ Action
                                ... 等々
    それぞれ型クラスの制約なんかが少しづつ違って
    いたりするので、必要に応じて Hackage を参照
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)
to 関数で関数適用

   to 関数を使えば、 (^.) で取得した値に対して関数
    適用できる

    (1, 2, 3)^._2.to (*100) -- => 200

   さらに関数合成を連ねて次のようにしても良い

    (1,(10,20),3)^._2.to swap._2.to (*100)
                             -- => 1000
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)
(.=) と 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
(.=) と use 関数
   (.=) や use の簡単な例:

    sample :: State Line ()
    sample = do
      -- (.=) で状態に代入
      startPoint .= Point { _x = 100, _y = 200 }
      endPoint.x .= 300

     -- 状態から値を取り出し
     sp <- use startPoint
     epx <- use $ endPoint.x

     return ()
各 Setter 演算子の
MonadState バージョン
   何処かの言語で見たような書き方ができる
    sample2 = do
      v %= (*100) --over

      v   += 10    -- 加算
      v   -= 10    -- 減算
      v   *= 10    -- 乗算
      v   //= 10   -- 除算

      b ||= True   --OR
      b &&= True   --AND

    ※ 「状態」に対してかなりやりたい放題できるように
    なるので乱用注意!
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
などなど

   Lens モジュールには Lens をより便利に使う仕組
    みが沢山用意されているので、 Hackage を一読し
    てみよう!



    http://hackage.haskell.org/package/lens-3.9.0.2
ところで・・・これは何だ・・・?
   Lens の構成図を見る
    と、さらに下層に ISO
    とか Equality とか
    ゆー輩がいます…が
         Lens

        ISO
         Equality


    勉強不足でご紹介で
    きないです orz
    ゴメンナサイ
まとめ的な何か
改めて Lens って何?

   レンズで覗くように複雑なデータ構造の内部に自在
    にアクセスする手段を提供してくれるライブラリ軍
   仕組みはやや複雑だけど Traversable を起点に
    考えていけば考え方はとっても明瞭
   単なるアクセサの域を超えた自在な操作を可能に
    するスーパーウルトラアルティメットアクセサ
   もうちょっと秘められたパワーがありそうです
大きいライブラリなので
尻込みしちゃうかもしれないけど
 Lens は全然怖くないよ!
Ekmett勉強会発表資料
!????
(((( ;゚ Д ゚ )))) こ・・・怖くねーし
Lens 全然怖くねーから・・・
さぁ、みんな Lens を使おう!




 ご清聴ありがとうございました!!

More Related Content

Ekmett勉強会発表資料

  • 1. Lens で Haskell をもっと格好良く! for 2013/3/31 ekmett 勉強会 ちゅーん
  • 2. 私はだあれ?  山手圏内で活動している 下っ端プログラマ  仕事の疲れは Haskell で癒す 日曜 Haskeller  Free モナドとか好きです  あと SDVX とか好き。音ゲーマーは Join me!
  • 3. 本日のメニュー  Lens とは何か  Lens でタプルを便利にする  任意のデータ型を Lens で使う  Lens の仕組ってどーなってんの?  Lens の便利な関数紹介  まとめ的な何か ※ ゆるふわ注意
  • 5. Lens とは・・・ タプルを始めとした任意のデータ構造の要素に対 する Setter や Getter を得るためのライブラリ Haskell で、 Java や C# といったオブジェクト指向 手続きプログラミングに似た記法で、要素にアクセ スできるようになる
  • 7. タプルの要素を取り出す方法  パターンマッチで取得する f (a, _, _) = a * 2  関数を定義して使う first (x, _, _) = x secound (_, x, _) = x third (_, _, x) = x g v = (first v) * 2
  • 8. ネストした内側の要素を取り出す  パターンマッチするとなんかキモい 全パターン網羅するとか無理ぽ f ((_, (_, _, x)), _, _) = x  関数合成を使えば綺麗&簡単 third.snd.first $ ((1, (1, 1, 999)), 1, 1) -- => 999
  • 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. ネストした内側の値を変更  素直に関数定義・・・超キモい 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. と に か く 超 不 満  値の取得と変更の識別子が異なる  タプルの要素数が異なると同じ識別子が使えない  構造がネストすると値の設定が超めんどい Java とか C# のような手続き言語で public 変数にアクセスするみたいに もっとスマートに構造を扱う事はできないの?
  • 12. と に か く 超 不 満  値の取得と変更の識別子が異なる  タプルの要素数が異なると同じ識別子が使えない  構造がネストすると値の設定が超めんどい そこで Lens ですよ!! Java とか C# のような手続き言語で public 変数にアクセスするみたいに もっとスマートに構造を扱う事はできないの?
  • 13. Lens のインストール  Cabal でいっぱつ $ cabal install lens  Hackage から直接アーカイブを取得 http://hackage.haskell.org/package/lens-3.9.0.2 コンパイルに時間がかかるので、 すごい H 本か TaPL あたりを読んでゆっくり待とう
  • 14. Lens を import  Haskell のソースコードに Import Control.Lens  あるいは、 ghci で :m Contorol.Lens
  • 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. ネストしたタプルから要素を取り出す  _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. 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. 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. 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. 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. ここまでのまとめ タプルの操作には不満がまんまん でも Lens を使えば・・・  値の取得も変更も同じ識別子で参照できる  ネストしたタプルの値の変更も 手続き言語の代入感覚でらくらく書ける  それでいてしっかり型安全 ( これ重要) タプル以外の型もこんな風にできない?→
  • 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. Point 単位の操作は簡単  取得 startPoint sampleLine -- => Point {x = 100, y = 150} endPoint sampleLine -- => Point {x = 200, y = 250}  置き換え SampleLine {    endPoint = Point { x = 1000, y = 1500 }}
  • 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. では、座標単位の操作は?  取得は関数合成を使えば良い 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. 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. 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. こんな場合はどうなる?  型変数が含まれる型でも 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. ここまでのまとめ 自分で作った型も Lens で操作したい! でも型とかややこしそうだし面倒では?  TemplateHaskell の力を借りて ちょ〜簡単に Lens になるよ  型変数を含む場合も無問題!  それでいてしっかり型安全 ( 大事なことなのでn (ry いったいどういう仕組みなんだろう?→
  • 32. Setter を作ろう  単純に 2 要素のタプルの 2 つめの要素を任意の 値に置き換える関数を考えると、次のような型にな る f :: a -> (b, c) -> (b, a)  これだけではつまらないので、一つ目の引数を関 数で取るようにする f :: (a -> b) -> (c, a) -> (c, b)
  • 33. Setter を作ろう  単純に 2 要素のタプルの 2 つめの要素を任意の 値に置き換える関数を考えると、次のような型にな る f :: a -> (b, c) -> (b, a) 値を x に置き換えたい場合は  const x を適用すれば良い これだけではつまらないので、一つ目の引数を関 数で取るようにする f :: (a -> b) -> (c, a) -> (c, b)
  • 34. ところで  この型、何かと似てない? f :: (a -> b) -> (c, a) -> (c, b) fmap :: Functor f => (a -> b) -> f a -> f b とそっくり・・・
  • 35. ところで  この型、何かと似てない? f :: (a -> b) -> (c, a) -> (c, b) ※ 衆知のとおり、 2 値のタプルは Functor になっ ていて、次のような事ができる fmap (*2) ("Hey!", 5) -- => ("Hey!",10) しかし Functor では一つ目の要素は操作できない さて、どうしよう?
  • 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. 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. 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. 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. 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. 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. 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. _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. 実際にやってみる  導きだした型を満足させるよう _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. こうなれば後は簡単  (.~) は次のようにして簡単に再実装できる (.~) :: 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. それじゃぁ次は 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. 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. 同じようにして 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. アクセサの定義、 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. (^.) の実装も超簡単 (^.) :: s -> Getting a s a -> a v ^. l = (foldMapOf l) id v 値をそのまま取り出したいのだから 引数に対して何もしない関数 id :: a -> a を、適用してやれば良い (111, 222)^._1 -- => 111 (111, 222)^._2 -- => 222
  • 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. 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. 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. _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. 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. 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. そんなワケで  今回再実装したオレオレ Lens も _1 や _2 を関数合成して、ネストしたタプルの好き な要素にアクセスできるよっ _2._1.~"Lens" $ ("Hello", ((), "World")) -- => ("Hello",("Lens","World")) ("Hello", ("Lens", "World"))^._2._1 -- => "Lens"
  • 58. (注)  今回の再実装で Id 、 Const という型を使ったが、 実際の Lens の実装では Mutator 、 Accessor と いう別実装を用いている これは、型エラーが発生した時に、よりエラーの原 因を特定しやすくするため。
  • 59. ここまでのまとめ Lens の仕組みって凄い複雑そう・・・ 超人的な知能を持っていないと理解できない んじゃ?  Traversable 型クラスの fmapDefault 関 数 /foldMapDefault 関数から、型を中心に 追っていけば自然と導き出せるよ! もっと Lens の事が知りたいな!→
  • 61. と、その前に・・・  Control.Lens モジュール内では、 Lens と同じよう な型に様々な別名が付けられていて・・・ ・ Lens ・ Getter ・ Setter ・ Fold ・ Action ... 等々 それぞれ型クラスの制約なんかが少しづつ違って いたりするので、必要に応じて Hackage を参照
  • 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. to 関数で関数適用  to 関数を使えば、 (^.) で取得した値に対して関数 適用できる (1, 2, 3)^._2.to (*100) -- => 200  さらに関数合成を連ねて次のようにしても良い (1,(10,20),3)^._2.to swap._2.to (*100)                          -- => 1000
  • 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. (.=) と 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. (.=) と 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. 各 Setter 演算子の MonadState バージョン  何処かの言語で見たような書き方ができる sample2 = do v %= (*100) --over v += 10 -- 加算 v -= 10 -- 減算 v *= 10 -- 乗算 v //= 10 -- 除算 b ||= True --OR b &&= True --AND ※ 「状態」に対してかなりやりたい放題できるように なるので乱用注意!
  • 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. などなど  Lens モジュールには Lens をより便利に使う仕組 みが沢山用意されているので、 Hackage を一読し てみよう! http://hackage.haskell.org/package/lens-3.9.0.2
  • 70. ところで・・・これは何だ・・・?  Lens の構成図を見る と、さらに下層に ISO とか Equality とか ゆー輩がいます…が Lens ISO Equality 勉強不足でご紹介で きないです orz ゴメンナサイ
  • 72. 改めて Lens って何?  レンズで覗くように複雑なデータ構造の内部に自在 にアクセスする手段を提供してくれるライブラリ軍  仕組みはやや複雑だけど Traversable を起点に 考えていけば考え方はとっても明瞭  単なるアクセサの域を超えた自在な操作を可能に するスーパーウルトラアルティメットアクセサ  もうちょっと秘められたパワーがありそうです
  • 76. (((( ;゚ Д ゚ )))) こ・・・怖くねーし Lens 全然怖くねーから・・・
  • 77. さぁ、みんな Lens を使おう! ご清聴ありがとうございました!!