module Control.LensFunction.Core where
import Prelude
import Data.Traversable (Traversable)
import Control.Applicative (Applicative, pure, (<*>))
import Control.Monad (ap)
import Control.LensFunction.Util
import Control.LensFunction.Exception
import Control.LensFunction.Internal
import qualified Control.Lens as L (Lens', lens)
import qualified Data.IntMap as IM
import Data.Maybe (fromJust)
import Control.Exception
lens' :: (s -> (v, v -> s)) -> L.Lens' s v
lens' f = \u s -> let (v,r) = f s
in fmap r (u v)
liftLens :: (a -> b) -> (a -> b -> a) -> (forall s. L s a -> L s b)
liftLens g p = liftI (lensI g p)
liftLens' :: (a -> (b, b -> a)) -> (forall s. L s a -> L s b)
liftLens' f = liftI (lensI' f)
dup :: Poset s => LensI s (s,s)
dup = lensI' $ \s -> ((s,s), \(t,t') -> lub t t')
class Poset s where
lub :: s -> s -> s
data Tag a = O { unTag :: a }
| U { unTag :: a }
instance Eq a => Poset (Tag a) where
lub (O a) (O b) | a == b = O a
lub (O _) (U b) = U b
lub (U a) (O _) = U a
lub (U a) (U b) | a == b = U a
lub _ _ = throw (NoLUBException "Control.LensFunction.lub")
instance (Poset a, Poset b) => Poset (a,b) where
lub (a,b) (a',b') = (lub a a', lub b b')
instance (Poset a, Eq (t ()), Traversable t) => Poset (t a) where
lub t1 t2 = if shape t1 == shape t2 then
fill t1 (zipWith lub (contents t1) (contents t2))
else
throw (NoLUBException "Control.LensFunction.lub")
data Diff t a = Diff (t ())
(IM.IntMap a)
(IM.IntMap (Tag a))
toDiff :: Traversable t => t a -> Diff t a
toDiff s = let om = IM.fromAscList $ zip [0..] (contents s)
in Diff (shape s) om IM.empty
fromDiff :: Traversable t => Diff t a -> t a
fromDiff (Diff sh om um) =
let cs = map (\i -> case IM.lookup i um of
Just v -> unTag v
Nothing -> fromJust $ IM.lookup i om) [0..]
in fill sh cs
instance Eq a => Poset (Diff t a) where
lub (Diff t1 o1 m1) (Diff t2 o2 m2)
= Diff t1 o1 (IM.unionWith lub m1 m2)
newtype L s a = L (Poset s => LensI s a)
unL :: L s a -> (Poset s => LensI s a)
unL (L s) = s
lift :: L.Lens' a b -> (forall s. L s a -> L s b)
lift l = liftI (fromLens l)
liftI :: LensI a b -> (forall s. L s a -> L s b)
liftI h = \(L x) -> L (h <<< x)
pair :: L s a -> L s b -> L s (a,b)
pair (L x) (L y) = L ((x *** y) <<< dup)
unit :: L s ()
unit = L $ lensI' (\s -> ( (), \() -> s ) )
unlift :: Eq a => (forall s. L s a -> L s b) -> L.Lens' a b
unlift f = toLens $ unL (f id') <<< tag
id' :: L (Tag s) s
id' = L $ lensI unTag (const U)
tag :: LensI s (Tag s)
tag = lensI O (const unTag)
unlift2 :: (Eq a, Eq b) => (forall s. L s a -> L s b -> L s c) -> L.Lens' (a,b) c
unlift2 f = toLens $ unL (f fst' snd') <<< tag2
fst' :: L (Tag a,b) a
fst' = L $ lensI (unTag . fst) (\(_,b) a -> (U a, b))
snd' :: L (a, Tag b) b
snd' = L $ lensI (unTag . snd) (\(a,_) b -> (a, U b))
tag2 :: LensI (a,b) (Tag a, Tag b)
tag2 = lensI (\(a,b) -> (O a, O b)) (\_ (a,b) -> (unTag a, unTag b))
unliftT :: (Eq a, Eq (t ()), Traversable t) =>
(forall s. t (L s a) -> L s b) -> L.Lens' (t a) b
unliftT f = toLens $
lensI' $ \s -> let l = makeLens s
in viewrefl l s
where
makeLens s = unL (f (projsV (shape s))) <<< diffL
tagT :: Functor f => LensI (f s) (f (Tag s))
tagT = lensI (fmap O) (\_ -> fmap unTag)
diffL :: Traversable t => LensI (t a) (Diff t a)
diffL = lensI' $ \s -> (toDiff s, fromDiff)
projsV :: Traversable t => t b -> t (L (Diff t a) a)
projsV sh =
let n = length (contents sh)
in fill sh $ map (projV sh) [0..n1]
projV :: Traversable t => t b -> Int -> L (Diff t a) a
projV _ i = L $ lensI' $ \(Diff s o _) ->
( fromJust (IM.lookup i o),
\v -> Diff s o (IM.singleton i (U v)))
projs :: Traversable t => t b -> t (L (t (Tag a)) a)
projs sh =
let n = length (contents sh)
in fill sh $ map (proj sh) [0..n1]
proj :: Traversable t => t b -> Int -> L (t (Tag a)) a
proj sh i = L $
lensI (\s -> unTag (contents s !! i))
(\s v -> fill sh (update i (U v) (contents s)))
update :: Int -> a -> [a] -> [a]
update 0 v (_:xs) = v:xs
update i v (x:xs) = x:update (i1) v xs
update _ _ _ = error "Invalid Index"
newtype R s a = R { unR :: Poset s => s -> (a, s -> Bool) }
instance Functor (R s) where
fmap f (R m) = R $ \s -> let (x, p) = m s in (f x, p)
instance Monad (R s) where
return x = R $ const (x, const True)
R m >>= f = R $ \s -> let (x,c1) = m s
(y,c2) = let R k = f x in k s
in (y, \t -> c1 t && c2 t)
instance Applicative (R s) where
pure = return
(<*>) = ap
observe :: Eq w => L s w -> R s w
observe l = R $ \s -> let w = get (unL l) s
in (w, \s' -> get (unL l) s' == w)
unliftM :: Eq a => (forall s. L s a -> R s (L s b)) -> L.Lens' a b
unliftM f = toLens $ lensI' $ \src -> viewrefl (makeLens src) src
where
makeLens src =
let (l,p) = unR (f id') (O src)
l' = unL l <<< tag
put' s v =
let s' = put l' s v
in if p (O s') then
s'
else
throw (ChangedObservationException "Control.Lens.Function.unliftM")
in lensI (get l') put'
unliftM2 :: (Eq a, Eq b) =>
(forall s. L s a -> L s b -> R s (L s c)) -> L.Lens' (a,b) c
unliftM2 f = toLens $ lensI' $ \src -> viewrefl (makeLens src) src
where
makeLens src =
let (l,p) = unR (f fst' snd') (get tag2 src)
l' = unL l <<< tag2
put' s v =
let s' = put l' s v
in if p (get tag2 s') then
s'
else
throw (ChangedObservationException "Control.LensFunction.unliftM2")
in lensI (get l') put'
unliftMT :: (Eq a, Eq (t ()), Traversable t) =>
(forall s. t (L s a) -> R s (L s b)) -> L.Lens' (t a) b
unliftMT f = toLens $ lensI' $ \src -> viewrefl (makeLens src) src
where
makeLens src =
let (l,p) = unR (f (projsV (shape src))) (get diffL src)
l' = unL l <<< diffL
put' s v =
let s' = put l' s v
in if p (get diffL s') then
s'
else
throw (ChangedObservationException "Control.LensFunction.unliftMT")
in lensI (get l') put'