haskellのlensの使い方 (詳しめ)
Lens
,Getter
,Setter
からEquality
,Iso
,Prism
,Review
に関して
Equality
type Equality s t a b = forall p f. p a (f b) -> p s (f t)
A witness that
(a ~ s, b ~ t)
.
- 図の一番下にある。
a
とs
,b
とt
が等しいことを示す。同時に2つの等号を表すのはlensとして使うためであろう。
type Equality s t a b = forall p f. p a (f b) -> p s (f t)
type Lens s t a b = forall f. Functor f => (a -> f b) -> s -> f t
のようにLens
と比較すると、その(->)
とFunctor
の制約が取り除かれていることが分かる。型は、任意の二項型構築子p
に対しa
,b
からs
,t
へはその上で変換できる、と言っている。このようなことが可能であるのはつまり、a
とs
,b
とt
が同一である時のみである。(あるいは型a
,b
を持つ値が存在しない時。)
- 抽象的過ぎて制約が強く逆に分かりやすい
- data
Identical
は、その値が存在することとa
とs
,b
とt
が同一であることが同値であるようにGADTsで定義されている- 面白い
type Foo = Int
fooIsInt :: Equality' Foo Int
fooIsInt = id
fooIsDouble :: Equality' Foo Double
fooIsDouble = id -- Couldn't match type `Double' with `Int'
Iso
type Iso s t a b = forall p f. (Profunctor p, Functor f) => p a (f b) -> p s (f t)
iso :: (s -> a) -> (b -> t) -> Iso s t a b
from :: Iso s t a b -> Iso b a t s
Mon Dec 22 23:05:12 JST 2014 : Iso
の型がLens
のそれになっていたので修正 @minpou_氏に感謝します
Isomorphism families can be composed with another
Lens
using(.)
andid
.
Equality
とLens
の間にある。同型を表わす- 同型とはざっくり言うとこの場合その型を持つ値の数が等しいことである
- 逆向きでも使える
Lens
from
は向きをひっくり返す- ひっくり返してもなお
Iso
- これも普通
Iso s t a b
でなくIso' s a
を使うと思う- そもそも
s = t, a = b
でないとGetter
のmethodが使えない
- そもそも
- 関数
iso
は右向きと左向きの2つの関数を与え、Iso
を作る- 合成しても
id
にならないものを与えることもできるが止めるべき
- 合成しても
makeLenses
は可能ならばIso
を作る
data Tribool = TTrue | TFalse | TUnkown
tribool :: Iso' (Maybe Bool) Tribool
tribool = iso f g where
f (Just True) = TTrue
f (Just False) = TFalse
f Nothing = TUnkown
g TTrue = Just True
g TFalse = Just False
g TUnkown = Nothing
>>> (Just True) ^. tribool
TTrue
>>> TUnkown ^. from tribool
Nothing
Lens
type Lens s t a b = forall f. Functor f => (a -> f b) -> s -> f t
lens :: (s -> a) -> (s -> b -> t) -> Lens s t a b
A
Lens s t a b
is a purely functional reference.
- 純粋関数的参照
Getter
かつSetter
依存
lens類全般に言えることだが、単なる関数であるのでlens packageに依存していなくてもLens
は作れる。
lens :: (s -> a) -> (s -> b -> t) -> (forall f. Functor f => (a -> f b) -> s -> f t)
lens sa sbt afb s = sbt s <$> afb (sa s)
なので、例えば
data Foo a = Foo { _bar :: Int, _baz :: Int, _quux :: a }
bar :: forall f. Functor f => (Int -> f Int) -> Foo a -> f (Foo a)
bar f s = (\ b -> s { _bar = b }) <$> f (_bar s)
のようにするとLens
ができる
Prism
type Prism s t a b = forall p f. (Choice p, Applicative f) => p a (f b) -> p s (f t)
prism :: (b -> t) -> (s -> Either t a) -> Prism s t a b
prism' :: (b -> s) -> (s -> Maybe a) -> Prism s s a b
A
Prism l
is aTraversal
that can also be turned around withre
to obtain aGetter
in the opposite direction.
- (値の範囲的な意味での)包含
Integetr
とNatural
とか
Lens
の隣りLens
と同じぐらい便利
作成:
import Numeric.Natural
nat :: Prism' Integer Natural
nat = prism toInteger $ \ i ->
if i < 0
then Left i
else Right (fromInteger i)
左から右へは変換できないことがあるが、右から左へは必ず変換できる。
>>> (3 :: Integer) ^? nat :: Maybe Natural
Just 3
>>> (-3 :: Integer) ^? nat :: Maybe Natural
Nothing
>>> (3 :: Natural) ^. re nat :: Integer
3
無理矢理Maybe
を剥がすこともできるし、添えることもできる。
>>> (3 :: Integer) ^?! nat :: Maybe Natural
3
>>> (-3 :: Integer) ^? nat :: Maybe Natural
*** Exception: (^?!): empty Fold
>>> (3 :: Natural) ^? re nat :: Maybe Integer
Just 3
re
はReview
の、(^?)
,(^?!)
はFold
のmethodである。またSetter
でもあり、Natural
であるときだけ2倍するといった操作も可能。
>>> (-3 :: Integer) & nat %~ (* 2)
-3
>>> (3 :: Integer) & nat %~ (* 2)
6
template haskell
makeLenses
の対応物makePrisms
が存在する。
data ABC = A | B Int | C Double String
makePrisms ''ABC
すると
_A :: Prism' ABC ()
_B :: Prism' ABC Int
_C :: Prism' ABC (Double, String)
が定義される。便利。
Review
type Review t b = forall p f. (Choice p, Bifunctor p, Settable f) => Optic' p f t b
unto :: (b -> t) -> Review s t a b
re :: Review s a -> Getter a s
un :: Getter s a -> Review a s
review :: Review t b -> b -> t
This is a limited form of a
Prism
that can only be used forre
operations.
Prism
の上、親はいないre
だけできるPrism
re
するとGetter
になる- 逆に
Getter
をun
するとReview
になる - といっても
Review
にしてもどうせ使うときはGetter
に戻して使ってる
- 逆に
review
も、re
してGetter
にしてview
してるだけ
>>> "hoge" ^. re (unto length)
4
ただし、
re (unto length)
= (re . un . to) length
= (re . un) (to length)
= to length
である。
Getter
type Getter s a = forall f. Gettable f => (a -> f a) -> s -> f s
to :: (s -> a) -> Getter s a
view :: Getter s a -> s-> a
(^.) = flip view
Sun Dec 21 20:35:39 JST 2014 : view, (^.) :: s -> Getter s a -> a
と表記していたので訂正
A
Getter s a
is just any function(s -> a)
, which …
- つまるところただの関数
Lens
やIso
はGetter
Review
と仲良しview
,(^.)
で元の普通の関数に戻る
>>> False ^. to show
"False"
つまり
x ^. to f = f x
である。
State
State
の上でも使える (正確にはMonadState s
)
use :: Getter s a -> State s a
Setter
type Setter s t a b = forall f. Settable f => (a -> f b) -> s -> f t
sets :: ((a -> b) -> s -> t) -> Setter s t a b
mapped :: Functor f => Setter (f a) (f b) a b
set, (.~) :: Setter s t a b -> b -> s -> t
over, (%~) :: Setter s t a b -> (a -> b) -> s -> t
A
Setter s t a b
is a generalization offmap
fromFunctor
.
- 曰く関手
mapped
の型を見ると分かりやすい
set
は値を代入over
は値を更新
>>> [1,2,3,4] & sets (\ f (x : xs) -> f x : xs) .~ 10
[10,2,3,4]
>>> [1,2,3,4] & mapped %~ (+ 10)
[11,12,13,14]
>>> [1,2,3,4] & mapped .~ 10
[10,10,10,10]
mapped
の例ではまさにmap
しているのが分かる。
State
Getter
のuse
同様、State
の上でも使える
assign, (.=) :: Setter s s a b -> b -> State s ()
(%=) :: Setter s s a b -> (a -> b) -> m ()
まとめ
Getter
は関数Setter
は関手Lens
はGetter
かつSetter
Review
は逆向きのGetter
Prism
はReview
かつSetter
Iso
は同型Equality
は同一性
This post is the No.15 article of Haskell Advent Calendar 2014
haskellのlensの使い方 (詳しめ)
- Sun Jun 21 01:59:23 JST 2015
- 次記事へのlinkを削除