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

Haskell-在另一种数据类型中使用一种数据类型,haskell,types,Haskell,Types,哈斯克尔新手;我希望能够声明Val,它可以是IntVal,StringVal-FloatVal和List,它可以是StringList,IntList,FloatList,其元素(相应地):StringVal,IntVal和FloatVal。 我迄今为止的努力: data Val = IntVal Int | FloatVal Float | StringVal String deriving Show data List = IntList [(IntVa

哈斯克尔新手;我希望能够声明
Val
,它可以是
IntVal,StringVal-FloatVal
List
,它可以是
StringList,IntList,FloatList
,其元素(相应地):
StringVal,IntVal和FloatVal
。 我迄今为止的努力:

data Val = IntVal Int
         | FloatVal Float
         | StringVal String deriving Show

data List = IntList [(IntVal Int)]
          | FloatList [(FloatVal Float)]
          | StringList [(StringVal String)] deriving Show
失败,错误为:

    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..)
实现这一目标的正确方法是什么

附言: 将列表声明为
data List=List[Val]
将允许如下列表: l=[(IntVal 10),(StringVal“Hello”)],这是我不允许的


我希望列表中的每个元素都是相同类型的

有一个使用GADT的解决方案。问题是,
IntVal
etc实际上不是类型,它们只是单个类型
Val
的构造函数(基本上也是支持模式匹配的函数)。因此,一旦创建了
Val
,关于它是哪种类型的值的信息在类型级别(即编译时)就完全丢失了

诀窍是用它包含的类型标记
Val

data Val a where
    IntVal :: Int -> Val Int
    FloatVal :: Float -> Val Float
    StringVal :: String -> Val String
然后,如果您有一个简单的列表
[Val a]
,它将已经是同质的。如果必须:

data List = IntList [Val Int]
          | FloatList [Val Float]
          ...
这有点不同,因为它“擦除”了列表的类型,例如,它可以区分int的空列表和float的空列表。您还可以对列表使用相同的GADT技巧

data List a where
    IntList :: [Val Int] -> List Int
    FloatList :: [Val Float] -> List Float
    ...
但在这种情况下,我认为更好的设计可能更简单

newtype List a = List [Val a]

所有这些不同设计之间的权衡实际上取决于您计划如何使用它们。

有一种使用GADT的解决方案。问题是,
IntVal
etc实际上不是类型,它们只是单个类型
Val
的构造函数(基本上也是支持模式匹配的函数)。因此,一旦创建了
Val
,关于它是哪种类型的值的信息在类型级别(即编译时)就完全丢失了

诀窍是用它包含的类型标记
Val

data Val a where
    IntVal :: Int -> Val Int
    FloatVal :: Float -> Val Float
    StringVal :: String -> Val String
然后,如果您有一个简单的列表
[Val a]
,它将已经是同质的。如果必须:

data List = IntList [Val Int]
          | FloatList [Val Float]
          ...
这有点不同,因为它“擦除”了列表的类型,例如,它可以区分int的空列表和float的空列表。您还可以对列表使用相同的GADT技巧

data List a where
    IntList :: [Val Int] -> List Int
    FloatList :: [Val Float] -> List Float
    ...
但在这种情况下,我认为更好的设计可能更简单

newtype List a = List [Val a]

所有这些不同设计之间的权衡实际上取决于您打算如何处理它们。

定义“失败”。检查错误消息是学习过程的一部分。
IntVal
/
FloatVal
/
StringVal
不是类型!定义“失败”。检查错误消息是学习过程的一部分。
IntVal
/
FloatVal
/
StringVal
不是类型!有没有一种不用GADT就能做到这一点的方法?可能是一种妥协solution@Ngm当然:
data List=IntList[Int]| FloatList[Float]| StringList[String]
。如果您不介意稍微多一些多态性,还有
data Val a=Val a
,在这种情况下,
IntVal
FloatVal
等都只是拼写为
Val
。但这并不妨碍使用
Val Bool
,或
Val[(字符串->双精度,IO())]
,或任何东西。如果您希望元素类型反映在构造函数的选择中,如您的问题所示,从有限的选项集中选择,那么GADT就是实现这一点的功能。@DanielWagner我试过了,问题是它不是真正的VAL列表,您需要一种将其转换为VAL的方法,但是,是的,这是一个很好的折衷解决方案,有没有一种不用GADT就能做到这一点的方法?可能是一种妥协solution@Ngm当然:
data List=IntList[Int]| FloatList[Float]| StringList[String]
。如果您不介意稍微多一些多态性,还有
data Val a=Val a
,在这种情况下,
IntVal
FloatVal
等都只是拼写为
Val
。但这并不妨碍使用
Val Bool
,或
Val[(字符串->双精度,IO())]
,或任何东西。如果您希望元素类型反映在构造函数的选择中,如您的问题所述,从有限的选项集中选择,那么GADT就是实现这一点的功能。@DanielWagner我确实尝试过,问题是这不是一个真正的VAL列表,您需要一种转换为VAL的方法,但是的,这是一个很好的折衷解决方案