对类型类型使用'fmap-like'函数*

时间:2015-10-17 03:36:54

标签: haskell type-kinds

假设我们将数据类型定义为

data A a = A' a deriving Show 

我们有

A :: * -> *

然后我们可以创建一个Functor的实例:

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

这允许我们创建A类型的值并使用fmap将函数应用于包装值

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

还可以使A成为Num的实例:

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

这两种方法都有效但是我有更好的方法吗?

1 个答案:

答案 0 :(得分:10)

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

这是mono-traversable包的目的,它提供MonoFunctor类型类。 A'的实例是:

type instance Element A' = Int

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

YMMV与简单的a'map :: (Int -> Int) -> A' -> A'函数或镜头相比有多大用处。