van Laarhoven lens

fp category haskell
2021-10-18
2021-11-11

basic Lensと

type Lens s a = forall f. Functor f => (a -> f a) -> (s -> f s)

の対応を見る

{-# LANGUAGE Rank2Types #-}
import Control.Applicative
import Control.Monad.Identity
 
type Lens s a = forall f. Functor f => (a -> f a) -> (s -> f s)
 
get :: Lens s a -> s -> a
get l = getConst . l Const
 
update :: Lens s a -> (a -> a) -> s -> s
update l m = runIdentity . l (Identity . m)
 
set :: Lens s a -> a -> s -> s
set l b a  = update l (const b) a
 
compose :: Lens b c -> Lens a b -> Lens a c
compose r s = s . r
 
fstL :: Lens (a, b) a
fstL f (x,y) = fmap (\a -> (a,y)) (f x)
 
sndL :: Lens (a, b) b
sndL x (a,b) = (,) a <$> x b
 
main = do
  print $ get fstL (1, 2)
  -- => getConst . (fstL Const) (1, 2)
  -- => getConst . (\x (a,b) -> (,b) <$> x a) (1, 2)
  -- => getConst . (\(a, b) -> (,b) <$> Const a) (1, 2)
  -- => getConst . ((,2) <$> Const 1)
  -- => getConst . (Const 1)
  -- => 1
  print $ update (fstL . sndL) (*2) ((3, 4), 5)
  -- like `pair.(fstL.sndL) *= 2`

Isomorphism Lens

{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE ExistentialQuantification #-}
import Data.Bifunctor
 
-- type Lens s a = exists r. s <-> (a, r)
 
-- isomorphisms/bijections between type 'a' & 'b'
-- Iso has isomorphism law: fw i . bw i = bw i . fw i = id
data Iso a b = Iso
  { fw :: a -> b
  , bw :: b -> a
  }
 
-- unpack the Iso type
data Lens s a = forall r. Lens (Iso s (a,r))
 
get :: Lens s a -> s -> a
get (Lens l) = fst . fw l
 
update :: Lens s a -> (a -> a) -> (s -> s)
update (Lens l) f = bw l . first f . fw l
 
-- TODO: how implement `compose`, `fstL`, `sndL` ?
 
main = do
  print 0
  -- print $ get sndL (1, 2)
  -- print $ update (fstL `compose` sndL) (*2) ((3, 4), 5)

参考文献