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
と に か く 超 不 満

   値の取得と変更の識別子が異なる
   タプルの要素数が異なると同じ識別子が使えな
    い
   構造がネストすると値の設定が超めんどい
      そこで Lens ですよ!!
    Java とか C# のような手続き言語で
    public 変数にアクセスするみたいに
    もっとスマートに構造を扱う事はできないの?
Lens のインストール
   Cabal でいっぱつ

$ cabal install lens


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


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


    コンパイルに時間がかかるので、
    すごい 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 を (.) で合成して、ネストした
         複雑なタプルの内側の値をピンポイントで取り
         出し
, (310, (321, 322, 323, 999, 325), 330), 400)^._3._2._4
                                     
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 ($) と外延的等価な (&) を使
     う 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

     置き換えは・・・いまいち分りづらい
           よし、 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)
         値を 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 型クラスで、次の型を持つ
         Id は 関数が定義されている
     traverseData.Functor.Identity の定義に同じ
                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 を別の関数と差し替えれば別の
     動きをするんじゃなイカ?というわけで ...
           これにより、 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 という別名
         当然、 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 =
                     型定義に登場しない型変数 m
            (a -> Const r a) -> s -> Const r s
    type Setter s t a b =
            コンパイルのため、 FoldMap の実装に合せ
            (a ->Monoid を要求するようにしておく
                  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
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
      える (*100) (1, 2, 3) -- => (1,200,3)
    (over _2)

    (foldMapOf y) (*2) $ Point { _x = 100, _y = 200 }
                  -- => 400

    (over x) (*2) $ Point { _x = 100, _y = 200 }
                    -- => Point {_x = 200, _y = 200}



_2 %~ (*100) $ (1, 2, 3) -- => (1,200,3)
 %~ は over の中置バージョン
to 関数で関数適用

     to 関数を使えば、 (^.) で取得した値に対して関
      数適用できる
      (1, 2, 3)^._2.to (*100) -- => 200

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

(10,20),3)^._2.to swap._2.to (*100)
                        -- =>
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 は全然怖くないよ!
!????
(((( ;゚ Д ゚ )))) こ・・・怖くねーし
 Lens 全然怖くねーから・・・
さぁ、みんな Lens を使おう!




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

Ekmett勉強会発表資料

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