Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell GHC泛型中的Rep类型_Haskell_Generic Programming - Fatal编程技术网

Haskell GHC泛型中的Rep类型

Haskell GHC泛型中的Rep类型,haskell,generic-programming,Haskell,Generic Programming,我试图构建一个Default类,它自动知道如何创建默认值。所以我读了这篇文章,我的问题归结为:为什么要进行这种类型检查: {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DefaultSignatures #-} import GHC.Generics -- From https://wiki.haskell.org/GHC.Generics (sort of) class GSeri

我试图构建一个
Default
类,它自动知道如何创建默认值。所以我读了这篇文章,我的问题归结为:为什么要进行这种类型检查:

{-# 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)
但事实并非如此

{-# 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
错误是:

• 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’

这里的编译器错误是有帮助的,但只是以一种恼人的方式,它确切地告诉你什么是错误的,而不是为什么它是错误的

应为类型,但“Rep a”的种类为“*->*”

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

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
    是一个虚拟类型,因此我们可以将表示类型重用为更高级别的类型()

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

我们通常可以忽略
p
,但在定义利用泛型的新类型类时除外。我们希望在类型上进行模式匹配,例如
D1('MetaData…)v1p
,但是我们需要一些处理额外参数的方法

然后一个技巧是将
D1('MetaData…)V1
视为更高级别的类型(如函子)。这是我们在
GDefault
中的
f

class GDefault f where
  gdef :: f a
是的,
a
永远是这个愚蠢的参数,我们永远不会使用它,但是作为线噪声的回报,我们在我们的实例中获得了在
f
上进行模式匹配的能力。下面是四个实例,它们允许产品类型的自动通用
def
实现(
:*:
为提升元组):

这与数字塔的一些合理默认值一起,将允许我们定义数据类型,如
data Foo=Foo Int Char Float派生(Show,Generic)
,并将
Show(def::Foo)
计算为
“Foo 0.0”

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

为了利用这个helper类,我们和您一样:

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
,这正是我们想要的


第一个类希望它的“参数”
f
具有种类
*->*
(因为它将其用作
f a
),但你的类参数
a
(属于
GDefault
)只需要一个类型(如此种类
*
),但是您仍然在向它输入某种类型的
*->*
。这个问题问的是什么还不清楚-typechecker告诉了您为什么后一个代码不能编译!即使你的“问题归结到这一点”,也许你应该描述一下实际的问题。我觉得自己很笨,这实际上是亚历克建议的。。。
class Default a where
  def :: a

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