Haskell 数据类型
假设我有一个这样的类型(有效):
data WAE = Num Float
| Id String
| With [(String, WAE)] WAE -- This works, but I want to define it as below
deriving(Eq, Read, Show)
我想要一个这样的类型(无效):
data WAE = Num Float
| Id String
| With [(Id, WAE)] WAE -- This doesn't work ("Id not in scope")
deriving(Eq, Read, Show)
为什么我不能在 Haskell 中这样做?有什么想法可以达到类似的效果吗?
Let's say that I have a type like this (that works):
data WAE = Num Float
| Id String
| With [(String, WAE)] WAE -- This works, but I want to define it as below
deriving(Eq, Read, Show)
I want a type like this (doesn't work):
data WAE = Num Float
| Id String
| With [(Id, WAE)] WAE -- This doesn't work ("Id not in scope")
deriving(Eq, Read, Show)
Why can't I do that in Haskell? Any ideas in achieveing a similar effect?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
![扫码二维码加入Web技术交流群](/public/img/jiaqun_03.jpg)
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
在 Haskell 中,有两个不同的名称空间。一种用于值,一种用于类型。诸如
Id
之类的数据构造函数位于值命名空间中,而诸如String
之类的类型构造函数以及类则位于类型命名空间中。这是可以的,因为没有上下文允许两者都被允许。在数据类型的定义中,两个命名空间并存,因为您定义了一个新的类型构造函数和几个新的数据构造函数,同时引用了现有的类型构造函数。
这里,
WAE
、Float
、String
、(,)
、[]
、Eq
、Read
和Show
都是类型世界中的名称,而Num
、Id< /code> 和
With
是值世界中的名称。混合它们没有任何意义,这就是为什么Id
不在第二段代码的范围内,因为您处于类型上下文中,并且没有称为ID 。
从你的问题来看,你想要做什么并不是100%清楚,但我怀疑它可能是这样的:
请注意,因为命名空间是不同的,所以在两者中都有一个名为
Id
的东西是完全可以的。In Haskell, there are two distinct namespaces. One for values, and one for types. Data constructors such as
Id
live in the value namespace, whereas type constructors such asString
, as well as classes live in the type namespace. This is OK because there is no context where both would be allowed.In the definition of a data type, the two namespaces live side by side, as you're defining a both a new type constructor and several new data constructors, while referring to existing type constructors.
Here,
WAE
,Float
,String
,(,)
,[]
,Eq
,Read
andShow
are all names in the world of types, whereasNum
,Id
andWith
are names in the world of values. Mixing them does not make any sense, and this is whyId
is not in scope in your second piece of code, as you are in a type context, and there is no type-level thing calledId
.It's not 100% clear from your question what you were trying to do, but I suspect it might be something like this:
Note that because the namespaces are distinct, it's perfectly fine to have something called
Id
in both.根据您的问题,我不完全确定您想要实现什么目标。 Haskell 的类型系统可以实现以下两种可能性。
然而,我不确定这是否是您想要的,因为它不仅仅允许在该对的第一部分中包含一个 id。
另一种可能性是为 id 创建一个新类型(或别名),如下所示:
请注意,MyId 也可以使用
newtype
或type
创建,每个都给出一个稍微不同的含义。但是,您不能使用
Id
,因为它是需要类型的数据构造函数。Based on your question, I'm not entirely sure what you are trying to accomplish. Here are two possibilities that are possible with Haskell's type-system.
I'm not sure this is what you want, however, because it allows for more than just an id in the first portion of the pair.
Another possibility is to create a new type (or alias) for the id, like so:
Note that MyId could also be created with either
newtype
ortype
, each giving a slightly different meaning.You cannot, however use
Id
as it is a data-constructor, where a type is expected.此处:
您在需要类型的上下文中使用数据构造函数
Id
。Id
的类型是WAE
,因此如果将此行更改为:它将编译,但结果可能不是您想要的。
如果您只是想表明所讨论的字符串在语义上是标识符,则可以使用类型别名:
Here:
you are using a data constructor
Id
in a context where a type is expected. The type ofId
isWAE
, so if you change this line to:it will compile, but the result is probably not what you want.
If you just want to show that the string in question is an identifier semantically, you can use a type alias: