我正在尝试学习GHC泛型。在回顾了几个示例之后,我想尝试创建一个通用的Functor
实例(不考虑GHC可以为我自动派生它们)。但是,我意识到我不知道如何使用Generics处理参数化的数据类型,我所看到的所有示例都是*
。这可能吗?如果可以,怎么办? (我也对其他类似的框架感兴趣,例如SYB。)
最佳答案
使用GHC Generics查找大量示例函数的最佳位置是 generic-deriving
package。那里是Functor
类的通用定义。从Generics.Deriving.Functor
复制(略有简化):
class GFunctor' f where
gmap' :: (a -> b) -> f a -> f b
instance GFunctor' U1 where
gmap' _ U1 = U1
instance GFunctor' Par1 where
gmap' f (Par1 a) = Par1 (f a)
instance GFunctor' (K1 i c) where
gmap' _ (K1 a) = K1 a
instance (GFunctor f) => GFunctor' (Rec1 f) where
gmap' f (Rec1 a) = Rec1 (gmap f a)
instance (GFunctor' f) => GFunctor' (M1 i c f) where
gmap' f (M1 a) = M1 (gmap' f a)
instance (GFunctor' f, GFunctor' g) => GFunctor' (f :+: g) where
gmap' f (L1 a) = L1 (gmap' f a)
gmap' f (R1 a) = R1 (gmap' f a)
instance (GFunctor' f, GFunctor' g) => GFunctor' (f :*: g) where
gmap' f (a :*: b) = gmap' f a :*: gmap' f b
instance (GFunctor f, GFunctor' g) => GFunctor' (f :.: g) where
gmap' f (Comp1 x) = Comp1 (gmap (gmap' f) x)
class GFunctor f where
gmap :: (a -> b) -> f a -> f b
default gmap :: (Generic1 f, GFunctor' (Rep1 f))
=> (a -> b) -> f a -> f b
gmap = gmapdefault
gmapdefault :: (Generic1 f, GFunctor' (Rep1 f))
=> (a -> b) -> f a -> f b
gmapdefault f = to1 . gmap' f . from1
要在数据类型上使用它,您必须派生
Generic1
而不是Generic
。 Generic1
表示形式的主要区别在于,它利用了对参数位置进行编码的Par1
数据类型。关于generics - 如何使用GHC.Generics(或其他类似框架)构造泛型Functor实例?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/17750867/