[Maybe a] mToL Nothing = [] mToL (Just xs) = ma...">

"Transposition" of functors?

I recently had to write the following function:

mToL :: Maybe [a] -> [Maybe a] mToL Nothing = [] mToL (Just xs) = map Just xs 

This raised the question of whether the above can be generalized:

 transposeF :: (Functor f, Functor g) => f (ga) -> g (fa) 

I assume that this only works if there is a way to β€œcollapse” f (ga) to fa , or is there another way?

+6
source share
4 answers

Actually there is a type class that supports this. It is not part of the standard type class, but "representable functors" have this feature.

The representative functor is an F functor with two things

  • type A
  • Isomorphism between F and (->) A

We could imagine it as

  type family ReprObj (f :: * -> *):: * class Functor f => Repr f where toHom :: fa -> (ReprObj f -> a) fromHom :: (ReprObj f -> a) -> fa 

where toHom . fromHom = fromHom . toHom = id toHom . fromHom = fromHom . toHom = id toHom . fromHom = fromHom . toHom = id . An example of a representable functor,

  newtype Pair a = Pair (a, a) deriving Functor type instance ReprObj Pair = Bool instance Repr Pair where toHom (Pair (a, b)) True = a toHom (Pair (a, b)) False = b fromHom f = Pair (f True, f False) 

Now, using this, we can get

 swap :: (Functor f, Functor g, Repr f, Repr g) => f (ga) -> g (fa) swap g = fromHom $ \obj -> fmap ($ obj) hom where hom = fmap toHom g 

In fact, we can also get a free applicative instance and a monad instance from representable functors. I described in detail how you could do this in a post.

+8
source

Traversable traversable typeclass provides sequence and sequenceA operations that provide the most common solutions to your problem, but they require various restrictions:

 sequence :: (Traversable t, Monad m) => t (ma) -> m (ta) sequenceA :: (Traversable t, Applicative f) => t (fa) -> f (ta) 
+13
source

This is generally impossible, no. Set f to Const b and g to Identity .

 newtype Const ba = Const { getConst :: b } newtype Identity a = Identity { runIdentity :: a } 

These are both explicit functors with their normal instances. transposeF cannot work because Const b does not provide any a for wrapping with Identity. Therefore, you cannot record the transpose function.

On the other hand, this is good for whole Functor parses. The categorical concept refers to the conjugate functor , and as soon as you see them, you will begin to see them everywhere. They are a very powerful concept in their own right.

+10
source

It is impossible to do this with functors simply because there is no general way to expand the value of a functor:

 Prelude> :info Functor class Functor f where fmap :: (a -> b) -> fa -> fb (GHC.Base.<$) :: a -> fb -> fa -- Defined in `GHC.Base' instance Functor Maybe -- Defined in `Data.Maybe' instance Functor (Either a) -- Defined in `Data.Either' instance Functor [] -- Defined in `GHC.Base' instance Functor IO -- Defined in `GHC.Base' instance Functor ((->) r) -- Defined in `GHC.Base' instance Functor ((,) a) -- Defined in `GHC.Base' 

Instead, you can create your own typeclass to provide a generic transpose function as follows:

 import Control.Applicative class Applicative f => Transposable t where unwrap :: ta -> a transpose :: s (ta) -> t (sa) transpose = fmap pure . unwrap 

The reason we make Applicative superclass of Transposable , so we can use its pure method. All Applicative instances are also Functor instances.

0
source

All Articles