2015-10-17 87 views
4

说我们有定义为的类型种类*

data A a = A' a deriving Show 

数据类型我们有

A :: * -> * 

然后我们就可以使Functor一个实例使用的“FMAP般”的功能:

instance Functor A where fmap f (A' x) = A' (f x) 

这使我们能够A类型的值,并使用fmap到App LY到包裹值的函数现在

Prelude> let x = A' 1 
Prelude> fmap (+1) x 
A' 2 

,如果我们定义A

data A = A' Int deriving Show 

那种A

A :: * 

因此,我们不能让A的实例Functor -

instance Functor A where fmap f (A' x) = A' (f x) 

<interactive>:4:18: 
    Kind mis-match 
    The first argument of `Functor' should have kind `* -> *', 
    but `A' has kind `*' 
    In the instance declaration for `Functor A' 

我的问题是,是否有一种通用的方法来将数据类型为*的数据类型的包装值应用到只包含一个参数的数据构造函数(即类似于fmap)?它很容易编写自定义功能:

Prelude> let myFmap f (A' x) = A' (f x) 
Prelude> let x = A' 1 
Prelude> myFmap (+1) x 
A' 2 

它也可能使ANum一个实例:

instance Num A where (+) (A' x) (A' y) = A' (x + y) -- Ignoring the warnings 
Prelude> A' 1 + A' 1 
A' 2 

这两种方法的工作,但在那里,我很想念更好的办法?

回答

10

我不认为在问题的后半部分有一个很好的通用解决方案,但我至少可以回答上半年的问题。

这是mono-traversable包的目的,它提供了MonoFunctor typeclass。对于A'实例是:如何有用,这是相对于简单的a'map :: (Int -> Int) -> A' -> A'功能或镜片

type instance Element A' = Int 

instance MonoFunctor a' where 
    omap f (A' i) = A' (f i) 

情况因人而异。

+1

请注意'lens'包中'iso'和可能'Wrapped'允许做类似的事情。 – mb14