我正在尝试学习如何使用GHC.Generics
. 一个有趣但令人生畏的话题。
在阅读博客文章24 Days of GHC Extensions: DeriveGeneric时,我学会了如何获取一个值并浏览它的Rep
. 好的。
然而,阅读博客文章Building data constructors with GHC Generics描述了构造Rep
和将其转换回一个值的类比,我被难住了。我已经阅读了 许多 其他资源, 但没有太大帮助。
在博客条目中是以下代码。首先,构建Rep
:
class Functor f => Mk rep f | rep -> f where
mk :: f (rep a)
instance Mk (K1 i c) ((->) c) where
mk = \x -> K1 x
instance (Mk l fl, Mk r fr) => Mk (l :*: r) (Compose fl fr) where
mk = Compose (fmap (\l -> fmap (\r -> l :*: r) mk) mk)
instance (Mk f f') => Mk (M1 i c f) f' where
mk = M1 <$> mk
然后,处理Compose
:
class Functor f => Apply f a b | f a -> b where
apply :: f a -> b
instance Apply ((->) a) b (a -> b) where
apply = id
instance (Apply g a b, Apply f b c) => Apply (Compose f g) a c where
apply (Compose x) = apply (fmap apply x)
然后处理类型歧义:
type family Returns (f :: *) :: * where
Returns (a -> b) = Returns b
Returns r = r
make :: forall b f z. (Generic (Returns b), Apply f (Returns b) b, Mk (Rep (Returns b)) f) => b
make = apply (fmap (to :: Rep (Returns b) z -> (Returns b)) (mk :: f (Rep (Returns b) z)))
哇。
真的,我一开始就被困在返回函子的Mk
班级mk
。我的问题:
什么是
mk
回归?为什么是函子?对其结果有何解释?我可以看到该K1 i c
实例Mk
返回一个函数(我知道这是一个函子),该函数接受一个值并将其包装在 中,但K1
我完全迷失了。mk
Mk (l :*: r)
Mk (M1 i c f)
我猜
Compose
来自Data.Functor.Compose
,这意味着当我这样做时fmap f x
,它会将fmap
两个级别深入到组合的函子中。但我无法fmap
理解Compose
.对于 的实例
M1 i c f
,我认为它只会将内部值包装在 中M1
,因此需要M1 <$> mk
或fmap M1 mk
对我来说没有意义。
显然,我并没有理解这些实例的意图或含义,以及这些实例如何交互以创建最终的Rep
. 我希望有人能启发我并提供一个很好的解释如何使用GHC.Generics
。