Haskell 使用约束类型写入GADT记录

Haskell 使用约束类型写入GADT记录,haskell,record,type-constraints,gadt,Haskell,Record,Type Constraints,Gadt,我的程序中编译了以下代码: {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE KindSignatures #-} {-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE TypeFamilies #-} class (Show (Data a)) => HasData (a :: *) where type Data a :: * data Fo

我的程序中编译了以下代码:

{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeFamilies #-}

class (Show (Data a)) => HasData (a :: *) where
    type Data a :: *

data Foo :: * -> * where
    Foo :: (HasData a) => String -> Data a -> Int -> Foo a -- bunch of args

deriving instance Show (Foo a)
由于
Foo
构造函数的参数数量可能很多,我希望使用记录语法编写代码,但我不知道如何使用GADT语法(GHC弃用的数据类型上下文,因此我试图避免它们):


我需要在
Foo
的构造函数中约束
a
,就像我在没有记录语法的情况下所做的那样。如何执行此操作?

您可以通过在构造函数类型中声明记录析构函数来实现此操作,如下所示:

{-# LANGUAGE GADTs #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeFamilies #-}

data Foo :: * -> * where
    Foo :: HasData a => { -- look - the context declared upfront
        getStr :: String, -- wow - function declaration in type sig!
        getData :: Data a, -- only allowed with a HasData instance
        getInt :: Int
    } -> Foo a 
但我怀疑有一种更简单的方法可以实现你想要做的事情,除非你用
a
类型做的事情比看起来更狡猾。这里有一个更简单的方法来坚持显示数据:

{-# LANGUAGE GADTs #-}
{-# LANGUAGE StandaloneDeriving #-}

data Bar a where
    Bar :: Show a => {
        getStr' :: String,
        getData' :: a, -- can Show 
        getInt' :: Int
    } -> Bar a -- have (Show a)
deriving instance Show (Bar a)
这种方法的好处是可以处理任意可显示的数据,而不需要创建
HasData
类的实例,也不需要使用所有这些编译器pragma,但只有当您的
HasData
类只是为了使内容可显示时,这种方法才对您有所帮助。你可能有更深层次的目标,我看不到


(您可能会考虑删除<代码>显示< /代码>上下文,除了您实际使用它的地方,以简化更多的事情并允许您生成函子实例。这将更简单,根本不需要任何编译器实用主义。多年来,我变得更喜欢保持事物的通用性,并生成函子实例。)

a的
数据是什么?您是否出于某种目的添加了幻影类型,因为您似乎没有任何
a
类型的内容,只有
数据a
类型的内容。(例如,如果您只是将
Show
上下文替换为构造函数,这将大大简化您的需求。)我遇到了一个与此无关的问题。我有点不在行,我不知道如何让
GADTs
工作。我为
KindSignatures
GADTs
添加了两个标题,现在可以使用了。相关的错误是:
非法种类签名“免费”(使用种类签名允许种类签名)
,现在我知道这意味着在
{-#…#-}
中创建一个头在第一个示例中,
HasData a=>Data a
的目的是什么?
HasData a=>{record}
难道不起作用吗?我原以为OP想要它,但在重读时,我发现这正是他们想要该上下文的地方,而不是指定他们想要确切地写在那里。(我觉得我本可以用更少的“that”来更清楚地表达,但失败了。)所以基本上我以为OP想要这个,但我现在明白了,我可能读得太多了,会把它删掉。@Eric谢谢;少一个分机。RankNTypes几乎肯定不是OP所追求的,它只会导致令人困惑的编译器错误。@chunksOf_50我想我是在问额外的约束是否意味着什么。它与单一约束有什么不同吗?使用RankNTypes,第二个
a
是否与第一个
a
不同?是-您只能使用类型为
HasData a=>Data a
的值,如中所示,在
HasData
的所有实例上都是多态的。实际上,很难产生这样的数据。
{-# LANGUAGE GADTs #-}
{-# LANGUAGE StandaloneDeriving #-}

data Bar a where
    Bar :: Show a => {
        getStr' :: String,
        getData' :: a, -- can Show 
        getInt' :: Int
    } -> Bar a -- have (Show a)
deriving instance Show (Bar a)