如何使用GHC.Generics(或其他类似的框架)构造泛型Functor实例? [英] How to construct generic Functor instances using GHC.Generics (or other similar frameworks)?

查看:136
本文介绍了如何使用GHC.Generics(或其他类似的框架)构造泛型Functor实例?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图学习GHC泛型。在回顾了几个例子之后,我想尝试创建一个通用的 Functor 实例(不管GHC能为我自动派生它们)。但是,我意识到我不知道如何使用泛型的参数化数据类型,我见过的所有示例都是 * 。这是可能的,如果是的话,如何? (我也对其他类似的框架感兴趣,例如SYB)。

解决方案

寻找大量示例的最佳位置使用GHC Generics的函数是 通用派生。那里有一个 Functor 类的通用定义。从 Generics.Deriving.Functor

  class复制(稍微简化) GFunctor'f其中
gmap'::(a - > b) - > f a - > fb

实例GFunctor'U1其中
gmap'_ U1 = U1

实例GFunctor'Par1其中
gmap'f(Par1 a)= Par1 (fa)

实例GFunctor'(K1 ic)其中
gmap'_(K1 a)= K1 a

实例(GFunctor f)=> GFunctor'(Rec1 f)其中
gmap'f(Rec1 a)= Rec1(gmap f a)

实例(GFunctor'f)=> GFunctor'(M1 i c f)其中
gmap'f(M1 a)= M1(gmap'f a)

实例(GFunctor'f,GFunctor'g)=> GFunctor'(f:+:g)其中
gmap'f(L1 a)= L1(gmap'fa)
gmap'f(R1 a)= R1(gmap'fa)

实例(GFunctor'f,GFunctor'g)=> GFunctor'(f:*:g)其中
gmap'f(a:*:b)= gmap'fa:*:gmap'fb

实例(GFunctor f,GFunctor'g )=> GFunctor'(f:.g)其中
gmap'f(Comp1 x)= Comp1(gmap(gmap'f)x)


class GFunctor f其中
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 数据类型。


I'm trying to learn GHC Generics. After reviewing several examples, I wanted to try to create a generic Functor instances (disregarding that GHC can derive them automatically for me). However, I realized I have no idea how to work with a parametrized data types with Generics, all the examples I've seen were of kind *. Is this possible, and if yes, how? (I'm also interested in other similar frameworks, such as SYB.)

解决方案

The best place to look for lots of example functions using GHC Generics is the generic-deriving package. There's a generic definition of the Functor class in there. Copying (slightly simplified) from 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

To use this on a datatype, you have to derive Generic1 rather than Generic. The key difference of the Generic1 representation is that it makes use of the Par1 datatype that encodes parameter positions.

这篇关于如何使用GHC.Generics(或其他类似的框架)构造泛型Functor实例?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆