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的方法,但是的,这是一个很好的折衷解决方案