Gus*_*ust 3 haskell algebraic-data-types
我试图将 of 的“数据项”ContentType与其内容相关联:
data ContentType = MyInt | MyBool deriving ( Show )
data Encoding'
= EncodingInt [Int]
| EncodingBool [Bool]
chooseContentType :: IO ContentType
chooseContentType = undefined
Run Code Online (Sandbox Code Playgroud)
我如何制作这样的东西,但经过类型检查?
data Encoding a =
Encoding { contentType :: ContentType
, content :: [a]
}
Run Code Online (Sandbox Code Playgroud)
您正在寻找的功能称为广义代数数据类型(或简称 GADT)。它是一个 GHC 扩展,因此您必须在文件顶部放置一个编译指示才能使用它们。(我还包括StandaloneDeriving,因为我们将使用它在一分钟内获取您的Show实例)
{-# LANGUAGE GADTs, StandaloneDeriving #-}
Run Code Online (Sandbox Code Playgroud)
现在您可以ContentType完全定义您的类型。这个想法是ContentType由其参数的(最终)类型参数化,因此ContentType将具有类型* -> *(即它将采用类型参数)。
现在我们要用一些有趣的语法来编写它。
data ContentType a where
MyInt :: ContentType Int
MyBool :: ContentType Bool
Run Code Online (Sandbox Code Playgroud)
这表明这MyInt不仅仅是一个ContentType;它是ContentType Int。我们让类型信息ContentType本身保持活跃。
现在Encoding基本上可以按照你的方式编写了。
data Encoding a =
Encoding { contentType :: ContentType a
, content :: [a]
}
Run Code Online (Sandbox Code Playgroud)
Encoding还接受一个类型参数a。其内容必须是 的列表a,并且其内容类型必须是支持该类型的内容类型a。由于我们的示例仅定义了两种内容类型,这意味着它必须是MyInt整数或MyBool布尔值,并且不支持其他编码。
我们可以通过一个子句恢复您的deriving (Show)on (这是我们在上面的编译指示中打开的第二个 GHC 扩展)ContentTypeStandaloneDeriving
deriving instance Show (ContentType a)
Run Code Online (Sandbox Code Playgroud)
这与您的子句等效deriving,只是它位于自己的行上,因为 GADT 语法实际上没有一个好的位置可以将其放在同一行中。