Intuitively, the unzip' function must tear down the structure holding (a,b) and then create it in two copies of the structure, the first of which contains a , and the second of them contains b .
One possible generalization already mentioned in another answer,
unzip' :: (Functor t) => t (a, b) -> (ta, tb) unzip' xs = (fmap fst xs, fmap snd xs)
This is consistent with the count, but one of the drawbacks is that it must go over the original structure twice - once for each fmap call.
The Foldable class describes structures that can be repeated, building the result as you move. We can use this property to ensure that we only go through the initial structure once (one call to foldr ), but we still need to know how to create copies of the structures again.
A class like MonadPlus provides ways to get an empty structure and merge two structures (a bit more Monoid ) -
class Monad m => MonadPlus m where mzero :: ma mplus :: ma -> ma -> ma
With this we can write
import Control.Monad import Data.Foldable (foldr) unzip' :: (Foldable t, MonadPlus m) => t (a, b) -> (ma, mb) unzip' = foldr f (mzero, mzero) where f (a,b) (as, bs) = (mplus (return a) as, mplus (return b) bs)
Then we can do things like
>> unzip' [(1,2), (3,4)] :: ([Int], [Int]) ([1,3],[2,4])
but also
>> unzip' (Right (1,2)) :: ([Int], Maybe Int) ([1],Just 2)
The last thought is a bit ugly that we need to call mplus (return a) as . It might be better to have a class like
class Listish m where null :: ma cons :: a -> ma -> ma
but I have not studied this bit of design space.