首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >GHC中的Rep型

GHC中的Rep型
EN

Stack Overflow用户
提问于 2016-09-21 14:45:23
回答 1查看 315关注 0票数 1

我正在尝试构建一个自动知道如何创建默认值的Default类。所以我读了关联维基页面,我的问题归结为:为什么这个打字员:

代码语言:javascript
复制
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DefaultSignatures #-}

import GHC.Generics

-- From https://wiki.haskell.org/GHC.Generics (sort of)
class GSerialize f where
  gput :: f a -> [Int]
class Serialize a where
  put :: a -> [Int]
  default put :: (Generic a, GSerialize (Rep a)) => a -> [Int]
  put a = gput (from a)

但这不是

代码语言:javascript
复制
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DefaultSignatures #-}

import GHC.Generics

class GDefault a where
  gdef :: a
class Default a where
  def :: a
  default def :: (Generic a, GDefault (Rep a)) => a
  def = gdef . from

错误是:

代码语言:javascript
复制
• Expecting one more argument to ‘Rep a’
  Expected a type, but ‘Rep a’ has kind ‘* -> *’
• In the first argument of ‘GDefault’, namely ‘Rep a’
  In the type signature:
    def :: (Generic a, GDefault (Rep a)) => a
  In the class declaration for ‘Default’
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-09-21 20:45:37

这里的编译器错误是有帮助的,但只有在这种恼人的方式下,它才能准确地告诉您出了什么问题,但没有告诉您错误的原因。

期望一个类型,但"Rep“有种类"* -> *”。

所以这里的问题是,Rep (一个类型家族)需要两个参数(在Rep a p中称为ap );它作为类型级别的函数将这两个类型参数映射为“泛型”类型。例如,

代码语言:javascript
复制
data Empty deriving Generic

instance Generic Empty where
  type Rep Empty =
    D1 ('MetaData "Empty" "Main" "package-name" 'False) V1

-- taken from https://hackage.haskell.org/package/base-4.9.0.0/docs/GHC-Generics.htm
  • a,例如Empty,代表了我们泛化的类型。
  • p是一种虚拟类型,因此我们可以将表示类型重用为更高级别的类型(在文件中)。

因此,在上面的示例中,Rep Empty p将简化为D1 ('MetaData ...) V1 p

我们通常可以忽略p,除非涉及到定义利用泛型的新类型。我们希望在像D1 ('MetaData ...) V1 p这样的类型上进行模式匹配,但是我们需要一些处理额外参数的方法。

然后,一个窍门就是把D1 ('MetaData ...) V1当作一个高级类型(像函子)。这是我们在f in GDefault

代码语言:javascript
复制
class GDefault f where
  gdef :: f a

是的,a永远是我们永远不会使用的愚蠢参数,但作为交换,我们可以在实例中对f进行模式匹配。以下四个实例允许产品类型的自动泛型def实现(:*:是一个提升的元组):

代码语言:javascript
复制
instance GDefault U1 where
  gdef = U1

instance Default a => GDefault (K1 i a) where
  gdef = K1 def

instance (GDefault a, GDefault b) => GDefault (a :*: b) where
  gdef = gdef :*: gdef

instance GDefault a => GDefault (M1 i c a) where
  gdef = M1 gdef

这与数字塔的一些合理的默认设置一起,将允许我们定义数据类型(如data Foo = Foo Int Char Float deriving (Show, Generic) ),并将show (def :: Foo)计算为"Foo 0 0 0.0"

您的代码有gdef :: a,这是错误的类型。我们需要gdef :: f a,因为类型是在类型* -> *的类型上定义的,因此出现了错误消息。

为了利用这个帮助者类,我们做了很多事情,就像您做的那样:

代码语言:javascript
复制
class Default a where
  def :: a

  default def :: (Generic a, GDefault (Rep a)) => a
  def = to gdef

to :: Rep a x -> a引入了一个虚假的x,它与我们的gdef :: f a联合生产f ~ Rep a,抛弃了x,这正是我们想要的。

包。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39619805

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档