{-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE RankNTypes #-}
module MicroLens where
import Control.Applicative import Data.Monoid importqualified Data.Traversable as T import Prelude hiding (sum) import Unsafe.Coerce
--------------------------------------------------------- -- Some basic libraries classProfunctor p where dimap :: (a' -> a) -> (b -> b') -> (p a b -> p a' b') dimap f g = lmap f . rmap g lmap :: (a' -> a) -> (p a b -> p a' b) lmap f = dimap f id rmap :: (b -> b') -> (p a b -> p a b') rmap f = dimap id f classProfunctor p => Choice p where left' :: p a b -> p (Either a c) (Either b c) right' :: p a b -> p (Either c a) (Either c b) instanceProfunctor (->) where dimap f g h = g . h . f instanceChoice (->) where left' f = either (Left . f) Right right' f = either Left (Right . f) classContravariant f where contramap :: (a' -> a) -> (f a -> f a')
-- Control.Applicative.Const replicated here for your -- convenience newtypeK b a = K { getK :: b } derivingFunctor instanceMonoid b => Applicative (Kb) where pure _ = K mempty K e <*> K f = K (e <> f) instanceContravariant (Kb) where contramap f (K b) = K b
newtypeId a = Id { getId :: a } derivingFunctor instanceApplicativeIdwhere pure = Id Id f <*> Id x = Id (f x)
--------------------------------------------------------- -- The lens types you'll implement
-- | Optic is the general pattern for all other lens types. typeOptic p f s t a b = p a (f b) -> p s (f t)
typeIso s t a b = forall p f . (Profunctor p, Functor f) => Optic p f s t a b
typeLens s t a b = forall f . Functor f => Optic (->) f s t a b
typeTraversal s t a b = forall f . Applicative f => Optic (->) f s t a b
typeFold s a = forall f . (Contravariant f, Applicative f) => Optic (->) f s s a a
typePrism s t a b = forall p f . (Choice p, Applicative f) => Optic p f s t a b
-- | A function which takes a lens and looks through it. -- The type given is specialized to provide a hint as to -- how to write 'view'. The more intuitive type for its use -- is -- -- @ -- view :: Lens s t a b -> (s -> a) -- @ view :: Optic (->) (K a) s t a b -> (s -> a) view l = getK . l K
-- | A function which takes a lens and a transformation function -- and applies that transformer at the focal point of the lens. -- The type given is specialized to provide a hint as to how to -- write 'over'. The more intuitive type for its use is -- -- @ -- over :: Lens s t a b -> (a -> b) -> (s -> t) -- @ over :: Optic (->) Id s t a b -> (a -> b) -> (s -> t) over l f = getId . l (Id . f)
-- | A function from a lens and a value which sets the value -- at the focal point of the lens. The type given has been -- specialized to provide a hint as to how to write 'set'. The -- more intuitive type for its use is -- -- @ -- set :: Lens s t a b -> b -> (s -> t) -- @ set :: Optic (->) Id s t a b -> b -> (s -> t) set l b = getId . l (Id . const b)
-- | A traversal which focuses on each element in any -- Traversable container. elements :: T.Traversable f => Traversal (f a) (f b) a b elements = T.traverse
-- | A function which takes a Traversal and pulls out each -- element it focuses on in order. The type has been -- specialized, as the others, but a more normal type might be -- -- @ -- toListOf :: Traversal s s a a -> (s -> [a]) -- @ toListOf :: Optic (->) (K (Endo [a])) s s a a -> (s -> [a]) toListOf l s = appEndo (getK $ l (\a -> K $ Endo (a:)) s) []
-- | A function which takes any kind of Optic which might -- be focused on zero subparts and returns Just the first -- subpart or else Nothing. -- -- @ -- preview :: Traversal s s a a -> (s -> Maybe a) -- @ preview :: Optic (->) (K (First a)) s s a a -> (s -> Maybe a) preview l s = getFirst (getK $ l (\a -> K $ First $ Just a) s)
-- | A helper function which witnesses the fact that any -- container which is both a Functor and a Contravariant -- must actually be empty. coerce :: (Contravariant f, Functor f) => f a -> f b coerce = contramap (const ()) . fmap (const ())
-- f a -> f Void
-- | A Fold which views the result of a function application to :: (a -> b) -> Fold a b to f g = contramap f . g . f
-- | A prism which focuses on the left branch of an Either _Left :: Prism (Either a x) (Either b x) a b _Left = rmap (either (fmap Left) (pure . Right)) . left' -- | A prism which focuses on the right branch of an Either _Right :: Prism (Either x a) (Either x b) a b _Right = rmap (either (pure . Left) (fmap Right)) . right'
-- | An iso which witnesses that tuples can be flipped without -- losing any information _flip :: Iso (a, b) (a, b) (b, a) (b, a) _flip = dimap swap (fmap swap) where swap (a, b) = (b, a)