monad-skeleton 0.1.2 → 0.1.2.1
raw patch · 2 files changed
+28/−5 lines, 2 filesPVP: minor bump suggested
API additions: PVP suggests at least a minor version bump
API changes (from Hackage documentation)
+ Control.Monad.Skeleton: debone :: Skeleton t a -> MonadView t (Skeleton t) a
+ Control.Monad.Skeleton: instance Functor m => Functor (MonadView t m)
Files
- monad-skeleton.cabal +1/−1
- src/Control/Monad/Skeleton.hs +27/−4
monad-skeleton.cabal view
@@ -1,5 +1,5 @@ name: monad-skeleton -version: 0.1.2 +version: 0.1.2.1 synopsis: An undead monad description: A simple operational monad based on Reflection without Remorse homepage: https://github.com/fumieval/monad-skeleton
src/Control/Monad/Skeleton.hs view
@@ -4,6 +4,7 @@ , iterMV , Skeleton , bone+ , debone , unbone , boned , hoistSkeleton) where@@ -16,22 +17,31 @@ import GHC.Prim import Prelude hiding (id, (.)) +-- | Re-add a bone. boned :: MonadView t (Skeleton t) a -> Skeleton t a boned t = Skeleton t id {-# INLINE boned #-} -unbone :: Skeleton t a -> MonadView t (Skeleton t) a-unbone (Skeleton (Return a) s) = case viewL s of+-- | Pick a bone from a 'Skeleton'.+debone :: Skeleton t a -> MonadView t (Skeleton t) a+debone (Skeleton (Return a) s) = case viewL s of Empty -> Return a Kleisli k :| c -> case k a of- Skeleton h t -> unbone $ Skeleton h (c . t)-unbone (Skeleton (t :>>= k) s) = t :>>= \a -> case k a of+ Skeleton h t -> debone $ Skeleton h (c . t)+debone (Skeleton (t :>>= k) s) = t :>>= \a -> case k a of Skeleton h t -> Skeleton h (s . t) +-- | Uncommon synonym for 'debone'.+unbone :: Skeleton t a -> MonadView t (Skeleton t) a+unbone = debone+{-# INLINE unbone #-}++-- | A skeleton that has only one bone. bone :: t a -> Skeleton t a bone t = Skeleton (t :>>= return) id {-# INLINABLE bone #-} +-- | Lift a transformation between bones into transformation between skeletons. hoistSkeleton :: (forall x. s x -> t x) -> Skeleton s a -> Skeleton t a hoistSkeleton f (Skeleton v c) = Skeleton (hoistMV f (hoistSkeleton f) v) (transCat (transKleisli (hoistSkeleton f)) c)@@ -41,16 +51,28 @@ (:>>=) :: t a -> (a -> m b) -> MonadView t m b infixl 1 :>>= +instance Functor m => Functor (MonadView t m) where+ fmap f (Return a) = Return (f a)+ fmap f (t :>>= k) = t :>>= fmap f . k+ {-# INLINE fmap #-}+ hoistMV :: (forall x. s x -> t x) -> (m a -> n a) -> MonadView s m a -> MonadView t n a hoistMV _ _ (Return a) = Return a hoistMV f g (t :>>= k) = f t :>>= g . k+{-# INLINE hoistMV #-} iterMV :: Monad m => (t a -> MonadView m t a) -> t a -> m a iterMV f = go where go t = case f t of m :>>= k -> m >>= go . k Return a -> return a+{-# INLINE iterMV #-} +-- | @'Skeleton' t@ is a monadic skeleton (operational monad) made out of 't'.+-- Skeletons can be fleshed out by getting transformed to other monads.+-- The implementation is based on+-- <http://wwwhome.cs.utwente.nl/~jankuper/fp-dag/pref.pdf Reflection without Remorse>+-- so it provides efficient ('>>=') and 'debone', monadic reflection. data Skeleton t a where Skeleton :: MonadView t (Skeleton t) x -> Cat (Kleisli (Skeleton t)) x a -> Skeleton t a @@ -76,6 +98,7 @@ viewL (Cat s) = case Seq.viewl s of Seq.EmptyL -> unsafeCoerce Empty a Seq.:< b -> unsafeCoerce (:|) a b+{-# INLINE viewL #-} instance Category (Cat k) where id = Cat Seq.empty