LoginSignup
7
1

More than 5 years have passed since last update.

lensの(^?)はなぜGetting (First a) s aを引数に取るのか

Last updated at Posted at 2017-08-16

結論

 Getting (First a) s aMaybe aを返せるようなPrism' s aの特殊化だから。
Getting (First a) s aPrism' s a

(^?)とは?

 Prismのアクセサです。
ちょうどLens(^.)と同じですが、PrismなのでMaybeで結果を返します。

(^?) :: s -> Getting (First a) s a -> Maybe a

 このようなPrismを作った時に使います。

Test.hs

{-# LANGUAGE TemplateHaskell #-}

module Test
  ( Foo(..)
  , _Bar
  , _Baz
  ) where

import Control.Lens (makePrisms)

data Foo = Bar Int
         | Baz Char

makePrisms ''Foo
-- 以下の関数がコンパイル時に定義される
-- _Bar :: (Choice p, Applicative f) => p Int  (f Int)  -> p Foo (f Foo)
-- _Baz :: (Choice p, Applicative f) => p Char (f Char) -> p Foo (f Foo)

Main.hs

import Test
import Control.Lens ((^?))

x :: Foo
x = Bar 10

y :: Foo
y = Baz 'a'

main :: IO ()
main = do
  print $ x ^? _Bar
  print $ x ^? _Baz
  print $ y ^? _Bar
  print $ y ^? _Baz

output

Just 10
Nothing
Nothing
Just 'a'

 Prismはこんな型です。

type Prism s t a b = forall p f. (Choice p, Applicative f) => p a (f b) -> p s (f t)
-- _Bar :: (Choice p, Applicative f) => p Int  (f Int)  -> p Foo (f Foo)
-- _Baz :: (Choice p, Applicative f) => p Char (f Char) -> p Foo (f Foo)

 しかしPrismのアクセサである(^?)は、
Prism s t a bではなくGetting (First a) s aを要求します。

type Getting r s a = (a -> Const r a) -> s -> Const r s

結論

 やはりGetter, GettingSetter, Settingの時と同じで、Getting (First a) s aPrism s t a bとして一般化できます。

type Prism s t a b = forall p f. (Choice p, Applicative f) => p a (f b) -> p s (f t)
type Getting r s a = (a -> Const r a) -> s -> Const r s

なぜなら……


 (->)Choiceなのでpに当てはまります。

instance Choice (->)

 First aMonoidで、かつConst (First r)Applicativeなので、
Const (First a)fに当てはまります。

instance Monoid (First a)
instance Monoid a => Applicative (Const a)

First aMaybe aと同型です)

 これを簡約すると

Getting (First a) s a = (a -> Const (First a) a) -> s -> Const (First a) s
Const (First a)を一般化) ==> forall f. Applicative f => (a -> f a) -> s -> f s
(->)を一般化)            ==> forall p f. (Choice p, Applicative f) => p a (f a) -> p s (f s)
                              = Prism s s a a
                              s,aを一般化) ==> Prism s t a b

となるので、Prism s t a bGetting (First a) s aの一般化です。


 それによりGetting (First a) s aPrism s s a aになるので、
(^?)はより特殊化された型Getting (First a) s aを受け取ります。
(特殊化することによりMaybe aを返せるようにしてるはず)

 Prism s s a aPrism' s aなので、上述の結論に帰着します。

 1,2ヶ月前にlensを使い始めたときからの疑問だったのですが、わかってしまえば最強ですね。
よっしゃ :dog2:

7
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
1