简体   繁体   English

Haskell-在另一种中使用一种数据类型

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM