Haskell 了解如何构建GHC.Generics Rep';s并转换回值
我正在努力学习如何使用。一个引人入胜但令人畏惧的话题 在阅读博客条目时,我学会了如何获取一个值并导航其Haskell 了解如何构建GHC.Generics Rep';s并转换回值,haskell,generics,ghc,ghc-generics,Haskell,Generics,Ghc,Ghc Generics,我正在努力学习如何使用。一个引人入胜但令人畏惧的话题 在阅读博客条目时,我学会了如何获取一个值并导航其Rep。好的 然而,读了一篇博客文章,其中描述了构建Rep并将其转换回一个值的类似过程,我被难住了。我已经通读了,但没有多大帮助 在博客条目中有以下代码。首先,构造Rep: class Functor f => Mk rep f | rep -> f where mk :: f (rep a) instance Mk (K1 i c) ((->) c) where m
Rep
。好的
然而,读了一篇博客文章,其中描述了构建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
然后处理类型歧义:
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
返回?为什么它是函子?对其结果的解释是什么?我可以看到Mk
的k1ic
实例返回一个函数(我知道这是一个函子),它接受一个值并将其包装在K1
中,但是Mk
对于Mk(l::::r)
和Mk(M1 I c f)
的我完全不知道
Compose
来自Data.Functor.Compose
,这意味着当我执行fmap fx
时,它会执行fmap
两个层次的组合函子。但是我无法理解Compose
中嵌套的fmap
sM1 i c f
的例子,我认为它只会将内部值包装在M1
中,因此需要M1 mk
或fmap M1 mk
对我来说毫无意义Rep
。我希望有人能给我一些启发,并在此过程中为如何使用GHC.Generics
提供一个很好的解释
mk
返回encode::generic a=>a->[Bool]
该函数将具有泛型实例的每个数据类型进行位序列化,他们定义了下面的类型类:
class Encode' rep where
encode' :: rep p -> [Bool]
通过为每个Rep类型(M1、K1等)定义Encode'
实例,他们使函数在每个数据类型上都通用
在中,作者的最终目标是一个泛型函数make::generic a=>TypeOfConstructor a
,因此可以天真地定义:
class Mk rep where
mk :: (? -> p) -- what should '?' be?
很快就意识到这是不可能的,因为有几个问题:
->
,haskell中的函数类型一次只接受一个参数,因此如果构造函数接受多个参数,mk
将无法返回任何合理的结果rep
类型有关p
。没有rep
上下文,就不可能派生:*:
或:+:
的实例,并且该函数将不再适用于任何嵌套数据类型A->b->c
的函数可以编码为Compose((>)A)((>)b)c
,它可以进一步组合,同时保留大量关于参数类型的信息。通过使其成为Mk
的类型参数,问题2也得以解决:
class Functor f => Mk rep f | rep -> f where
mk :: f (rep p)
其中,f
是对组合f g
和(>)a
的泛化,其中包含用于构造rep p
的类型级信息,即a->b->c->中最终->
之前的所有内容…->rep p
Compose
来自Data.Functor.Compose
,这意味着当我执行fmap fx
时,它会执行fmap
两个层次的组合函子。但是我无法理解Compose
中嵌套的fmap
s李>
在:*:
的Mk
实例中:
instance (Mk l fl, Mk r fr) => Mk (l :*: r) (Compose fl fr) where
mk = Compose (fmap (\l -> fmap (\r -> l :*: r) mk) mk)
fmap
仅更改嵌套组合的最内部类型,在这种情况下更改n元函数的最终结果mk
这里是字面上连接两个参数列表fl
和fr
,将它们的结果放入一个产品类型,即
f :: Compose ((->) a) ((->) b) (f r)
g :: Compose ((->) c) ((->) d) (g r)
mk f g :: Compose (Compose ((->) a) ((->) b)) (Compose ((->) c) ((->) d)) ((:*:) f g r)
-- or unwrapped and simplified
(a -> b -> r) -> (c -> d -> r') -> a -> b -> c -> d -> (r, r')
M1 i c f
的例子,我认为它只会将内部值包装在M1
中,因此需要M1 mk
或fmap M1 mk
对我来说毫无意义它只将内部值包装在
M1
中,但不清楚底层f
的参数列表有多长。如果它接受一个参数,那么mk
是一个函数,否则它是一个组合fmap
包装了两者的最内在价值。注意,这里有两个独立的设计“目标”(可以这么说)——一般地派生一个函数,并使该函数“很好”。作者想写一个多元函数,比如a->b->…->R
而不是Mk
类生成的Compose
链:Compose((>)a)(Compose((>)b)…R
。如果您试图理解泛型,我认为您可以忽略除Mk
类以外的所有内容,它是泛型的主要工具。我不知道作者为什么选择使用Compose编写所有内容,然后将其“转换”为多变量函数。
f :: Compose ((->) a) ((->) b) (f r)
g :: Compose ((->) c) ((->) d) (g r)
mk f g :: Compose (Compose ((->) a) ((->) b)) (Compose ((->) c) ((->) d)) ((:*:) f g r)
-- or unwrapped and simplified
(a -> b -> r) -> (c -> d -> r') -> a -> b -> c -> d -> (r, r')