Haskell:为什么用户自定义枚举的算术序列需要额外的空格?

20

对于Haskell中的任何内置类型,我都可以构建一个算术序列,就像这个例子(对于IntInteger等类型):

[1..5]

但如果我定义了一个枚举类型:

data Suit = Club | Diamond | Heart | Spade deriving (Show, Enum) 

当我创建等差数列时,我必须在枚举实例和点点之前加上空格,例如:

[Club .. Diamond]

为什么?


3
注意,这是一个“范围”而不是“列表推导式”。列表推导式是类似 [ f(x) | x <- myList ] 的表达式。 - Daniel McLaury
2
这不是列表推导,而是算术序列。除此之外,好问题+1。 - Henri Menke
2
这是 GHC 特有的吗?你尝试过其他 Haskell 编译器吗?这似乎是一种解析怪异现象。 - Henri Menke
1
@HenriMenke 这不是 GHC 特有的行为--这是规范中正确的行为--但无人能否认这确实是一种奇怪的解析。说实话,我有点惊讶这是第一次在 Stack Overflow 上出现这种情况。 - Daniel Wagner
啊哈,这不是第一次了。=) - Daniel Wagner
1个回答

24
问题在于,根据Haskell的词法规则modid.varsym是模块中变量的引用。 modid是由一个或多个大写标识符组成的序列,用点分隔,而varsym是一个符号名称。 Club是一个有效的modid.是一个有效的varsym(请注意,甚至在Prelude中有一个名为该名称的运算符,可以通过Prelude..访问)。 因此,X..被视为模块X中名为.的变量的限定名称。

因此,Club..Diamond被标记为“限定变量名称、构造函数名称”,而不是“构造函数名称、点点、构造函数名称”1。当它尝试解析限定变量名称时,它会失败,因为实际上没有名为Club的模块。

问题不会发生在[1..5],因为1不是有效的模块名称,也没有其他方式可以使1..1.形成有效的令牌。请注意,与某些语言不同,1.不允许作为写入1.0的更短方式。如果是这样,你将遇到类似的问题,因为1..5现在将被标记为“数字、点号、数字”。但它没有这样的情况,所以问题不会出现。

1“合格的变量名”胜过“构造函数名称,点点”,因为最大匹配规则认为当有多个可能性来匹配一个令牌时,应该选择从当前位置匹配最长子串的那个。


1
我是错了还是他们想在 Haskell 2010 中摆脱这种解析怪异性呢?(即,禁止 X.. 表示模块 X 的变量 .,而强制你写 X.(.) 来表示,这将消除这个词汇问题)。 - Giacomo Alzetta

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接