假设我们将数据类型定义为
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
这两种方法都有效但是我有更好的方法吗?
答案 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'
函数或镜头相比有多大用处。