{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE DeriveFunctor #-} module Data.Functor.Context ( Ctxt(..), toCtxt, mapCtxt, extractCtxt, addCtxt, ) where import Control.Comonad import Control.Applicative import Control.Lens.Wrapped import Control.Lens.Iso -- | A value with a possible predecessor and successor. -- Can be used to traverse values with their immediate context. newtype Ctxt a = Ctxt { getCtxt :: (Maybe a, a, Maybe a) } deriving (Functor, Eq, Ord) instance Show a => Show (Ctxt a) where show (Ctxt vs) = "toCtxt " ++ show vs instance Wrapped (Ctxt a) where type Unwrapped (Ctxt a) = (Maybe a, a, Maybe a) _Wrapped' = iso getCtxt Ctxt instance Rewrapped (Ctxt a) (Ctxt b) instance Applicative Ctxt where pure x = Ctxt (Nothing, x, Nothing) Ctxt (b,x,a) <*> Ctxt (b',x',a') = Ctxt (b <*> b', x x', a <*> a') -- instance Comonad Ctxt where -- extract (Ctxt (b,x,a)) = x -- duplicate (Ctxt (Nothing,x,Nothing)) = Ctxt (Nothing, Ctxt (Nothing, x, Nothing), Nothing) -- duplicate (Ctxt (Just b,x,Nothing)) = Ctxt (Ctxt Just b, Ctxt (Just b, x, Nothing), Nothing) -- duplicate (Ctxt (Nothing,x,Just a)) = Ctxt (Nothing, Ctxt (Nothing, x, Just a), Just a) -- duplicate (Ctxt (Just b,x,Just a)) = Ctxt (b, Ctxt (b, x, Just a), Just a) toCtxt = Ctxt mapCtxt :: (a -> b) -> Ctxt a -> Ctxt b mapCtxt = fmap extractCtxt :: Ctxt a -> a extractCtxt (Ctxt (_,x,_)) = x addCtxt :: [a] -> [Ctxt a] addCtxt = fmap Ctxt . withPrevNext where withPrevNext :: [a] -> [(Maybe a, a, Maybe a)] withPrevNext xs = zip3 (pure Nothing ++ fmap Just xs) xs (fmap Just (tail xs) ++ repeat Nothing)