concrete functor and monad transformers
#52Add a lifted identity functor
Feel free to change the lousy title of this ticket. The following very boring type is often useful when laziness needs to be managed in a fine-grained manner:
data Box a = Box {unBox :: a}
deriving (Show, Read, Eq, Ord)
instance Functor Box where
fmap f (Box a) = Box (f a)
instance Applicative Box where
Box f <*> Box x = Box (f x)
instance Monad Box where
Box x >>= f = f x
-- etc
For example, you can write a strict mapping function like this:
strictMap :: Traversable t => (a -> b) -> t a -> t b
strictMap f = unBox . traverse (\a -> Box $! f a)
To write a strict traversing function, you need to take it up a level, to the lifted identity monad transformer:
newtype BoxT m a = BoxT {runBoxT :: m (Box a)}
instance Functor m => Functor (BoxT m) where
fmap f (BoxT mba) = BoxT (fmap (fmap f) mba)
instance Applicative m => Applicative (BoxT m) where
pure = BoxT . pure . Box
BoxT m <*> BoxT n = BoxT $ (<*>) <$> m <*> n
instance Monad m => Monad (BoxT m) where
BoxT m >>= f = BoxT $ m >>= \(Box a) -> runBoxT (f a)
instance MonadTrans BoxT where
lift = BoxT . fmap Box
Now you can write
strictTraverse :: (Traversable t, Applicative f)
=> (a -> f b) -> t a -> f (t b)
strictTraverse f = fmap unBox . runBoxT . traverse (\a -> BoxT ((Box $!) <$> f a))
Do you think it would make sense to add such types to transformers
?
- description updated
It does seem reasonable. Lifting is the usual name, because it adds an extra bottom to the cpo of the type, but that name is overloaded.