module Ideas.Common.Traversal.Utils
(
Update(..), current, change, replace, changeM, changeG
, Focus(..), liftFocus, unliftFocus
, Wrapper(..), liftWrapper, unliftWrapper, mapWrapper
, Mirror, makeMirror
, (>|<), safe, fixp, fixpl, mplus, (>=>)
) where
import Control.Monad
import Data.Maybe
class Update f where
update :: f a -> (a, a -> f a)
current :: Update f => f a -> a
current = fst . update
change :: Update f => (a -> a) -> f a -> f a
change f = (\(x, g) -> g (f x)) . update
replace :: Update f => a -> f a -> f a
replace = change . const
changeM :: Update f => (a -> Maybe a) -> f a -> Maybe (f a)
changeM = changeG
changeG :: (Update f, Monad g) => (a -> g a) -> f a -> g (f a)
changeG f a = (`replace` a) <$> f (current a)
class Focus a where
type Unfocus a
focus :: Unfocus a -> a
focusM :: Unfocus a -> Maybe a
unfocus :: a -> Unfocus a
focus = fromMaybe (error "no focus") . focusM
focusM = Just . focus
liftFocus :: Focus a => (Unfocus a -> Maybe (Unfocus a)) -> a -> Maybe a
liftFocus f = fmap focus . f . unfocus
unliftFocus :: Focus a => (a -> Maybe a) -> Unfocus a -> Maybe (Unfocus a)
unliftFocus f = fmap unfocus . f . focus
class Wrapper f where
wrap :: a -> f a
unwrap :: f a -> a
liftWrapper :: (Monad m, Wrapper f) => (a -> m a) -> f a -> m (f a)
liftWrapper f = fmap wrap . f . unwrap
unliftWrapper :: (Monad m, Wrapper f) => (f a -> m (f a)) -> a -> m a
unliftWrapper f = fmap unwrap . f . wrap
mapWrapper :: Wrapper f => (a -> a) -> f a -> f a
mapWrapper f = wrap . f . unwrap
newtype Mirror a = Mirror { fromMirror :: a }
deriving (Show, Eq)
instance Wrapper Mirror where
wrap = Mirror
unwrap = fromMirror
makeMirror :: a -> Mirror a
makeMirror = wrap
infixr 0 >|<
(>|<) :: (a -> Maybe a) -> (a -> Maybe a) -> a -> Maybe a
(f >|< g) a = f a `mplus` g a
safe :: (a -> Maybe a) -> a -> a
safe f a = fromMaybe a (f a)
fixp :: (a -> Maybe a) -> a -> a
fixp f = last . fixpl f
fixpl :: (a -> Maybe a) -> a -> [a]
fixpl f a = a : maybe [] (fixpl f) (f a)