"换位"函子?

时间:2014-04-23 13:54:08

标签: haskell functor category-theory

最近我不得不写下面这个函数:

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

这就提出了一个问题:是否有可能将上述内容概括为:

transposeF :: (Functor f, Functor g) => f (g a) -> g (f a)

我想这只有在将f (g a)“崩溃”到f a时才有效,或者还有其他办法吗?

4 个答案:

答案 0 :(得分:13)

The Traversable typeclass提供了sequencesequenceA操作,这些操作为您的问题提供了最常用的解决方案,但它们需要不同的约束:

sequence :: (Traversable t, Monad m) => t (m a) -> m (t a)

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

答案 1 :(得分:10)

这一般是不可能的,不。将f设为Const b,将g设为Identity

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

这些都是具有正常实例的显然算子。 transposeF无法正常工作,因为Const b不提供用于包装Identity的任何a。所以你不能写转置函数。

另一方面,对于很多Functor配对来说这很好。分类概念是adjoint functor的概念,一旦你看到它们,你就会开始到处看到它们。它们本身就是一个非常强大的概念。

答案 2 :(得分:8)

实际上,有一个类型类可以支持这个。它不包含在标准类型类中,但是"可表示的仿函数"有这种能力。

代表性仿函数是一个带有两件事的仿函数F

  1. 类型A
  2. F(->) A
  3. 之间的同构

    我们可以将其表示为

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

    其中toHom . fromHom = fromHom . toHom = id。可表示的仿函数的一个例子,

     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)
    

    现在使用这个我们可以派生

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

    事实上,我们也可以从可表示的仿函数中获得一个免费的applicative和monad实例。我详细介绍了如何在blog post中完成此操作。

答案 3 :(得分:0)

使用仿函数是不可能的,因为没有通用的方法来展开仿函数值:

Prelude> :info Functor
class Functor f where
  fmap :: (a -> b) -> f a -> f b
  (GHC.Base.<$) :: a -> f b -> f a
    -- 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'

相反,您可以创建自己的类型类以提供通用transpose函数,如下所示:

import Control.Applicative

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

我们ApplicativeTransposable超类的原因是我们可以使用其pure方法。 Applicative的所有实例也是Functor的实例。