Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Repacking monads -- any generic way?

Tags:

haskell

monads

Given two monads, Monad m and Monad n, I would like to transform m (n a) into n (m a). But there seems to be no generic way because both (>>=) and return deals with only one monad type, and although (>>=) allows extracting content from a monad, you must pack them back to the same monad type so it can be a result value.

However, if we set m to a fixed type, the job becomes easy. Take Maybe as an example:

reorder :: (Monad n) => Maybe (n a) -> n (Maybe a)
reorder Nothing = return Nothing
reorder (Just x) = do
    x' <- x
    return $ Just x'

Or a list:

reorder :: (Monad n) => [n a] -> n [a]
reorder [] = return []
reorder (x:xs) = do
    x'  <- x
    xs' <- reorder xs
    return (x':xs')

Not hard to see, we've got a pattern here. To be more obvious, write it in a Applicative way, and it's no more than applying the data constructor to each element:

reorder (Just x) = Just <$> x
reorder (x:xs) = (:) <$> x <*> (reorder xs)

My question is: does a haskell typeclass already exist to describe such operations, or do I have to invent the wheel myself?

I had a brief search in the GHC documentation, and found nothing useful for this topic.

like image 792
hpsMouse Avatar asked Mar 13 '12 12:03

hpsMouse


1 Answers

Data.Traversable provides what you are looking for:

sequenceA :: (Traversable t, Applicative f) => t (f a) -> f (t a)

GHC even provides support for automatically deriving instances:

{-# LANGUAGE DeriveFunctor, DeriveFoldable, DeriveTraversable #-}
import Data.Foldable
import Data.Traversable

data List a = Nil | Cons a (List a) 
  deriving(Functor, Foldable, Traversable)
like image 173
rp123 Avatar answered Oct 03 '22 10:10

rp123