[英]Haskell - Using one data type kind in another
Haskell newbie; Haskell新手; I want to be able to declare
Val
which can be either IntVal, StringVal FloatVal
and a List
which can be either StringList, IntList, FloatList
, whose elements are (correspondingly): StringVal, IntVal and FloatVal
. 我希望能够声明
Val
,它可以是IntVal, StringVal FloatVal
,也可以是一个List
,可以是StringList, IntList, FloatList
,其元素是(相应地): StringVal, IntVal and FloatVal
。 My attempt so far: 到目前为止我的尝试:
data Val = IntVal Int
| FloatVal Float
| StringVal String deriving Show
data List = IntList [(IntVal Int)]
| FloatList [(FloatVal Float)]
| StringList [(StringVal String)] deriving Show
fails with the error: 失败并显示以下错误:
Not in scope: type constructor or class ‘IntVal’
A data constructor of that name is in scope; did you mean DataKinds?
data List = IntList [(IntVal Int)]
... (similarly for StringVal, FloatVal..)
what is the right way to achieve this? 什么是实现此目标的正确方法?
PS: declaring List as data List = List [Val]
ends up allowing Lists as follows: l = [(IntVal 10),(StringVal "Hello")], which I do not want to allow. PS:将列表声明为
data List = List [Val]
最终允许List如下:l = [(IntVal 10),(StringVal“ Hello”)],我不想允许。
I want each element of list to be a Value
of same kind 我希望列表的每个元素都是相同的
Value
There is a solution using GADTs. 有使用GADT的解决方案。 The problem is that
IntVal
etc are not actually types, they are just constructors (basically functions that also support pattern matching) for the single type Val
. 问题在于
IntVal
等实际上不是类型,它们只是单个类型Val
构造函数(基本上也支持模式匹配的函数)。 So once you have made a Val
, the information about which kind of value it is is completely lost at the type level (that is, compile time). 因此,一旦创建了
Val
,有关类型的值的信息就会在类型级别(即编译时)完全丢失。
The trick is to tag Val
with the type it contains. 诀窍是用
Val
包含的类型标记Val
。
data Val a where
IntVal :: Int -> Val Int
FloatVal :: Float -> Val Float
StringVal :: String -> Val String
Then if you have a plain list [Val a]
it will already be homogeneous. 然后,如果您有一个简单列表
[Val a]
,它将已经是同质的。 If you must: 如果你必须:
data List = IntList [Val Int]
| FloatList [Val Float]
...
which is slightly different in that it "erases" the type of list, and it can distinguish between an empty list of ints and an empty list of floats, for example. 这与“擦除”列表的类型略有不同,例如,它可以区分空白的int列表和空白的floats列表。 You could also use the same GADT trick with List
您也可以对List使用相同的GADT技巧
data List a where
IntList :: [Val Int] -> List Int
FloatList :: [Val Float] -> List Float
...
but in that case I think a better design is probably the simpler 但在那种情况下,我认为更好的设计可能更简单
newtype List a = List [Val a]
The trade-offs between all these different designs really depends on what you are planning to do with them. 所有这些不同设计之间的权衡实际上取决于您打算如何处理它们。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.