从各种OO语言的背景来到Haskell,对我来说似乎有点不利的一点是函数和字段名称的范围不是它们所关联的类型,所以它很容易运行如果不同的数据类型具有相同名称的字段,则为冲突。
如果我有这三个模块:
module One where
data Foo a = Foo { value :: a }
----
module Two where
data Bar a = Bar { value :: a }
----
module Three where
import One
import Two
foo = Foo { value = 42 } -- compile error here
n = value foo -- and here
模块value
中对Three
的非限定引用被认为是不明确的,即使这两个导入的名称中只有一个在此上下文中有意义。 (在OO语言中,对foo.value
和bar.value
的引用将是明确的。)
当然,我可以通过编写Foo { One.value = 42 }
来消除歧义,但这看起来很尴尬。我也可以不同地命名字段,例如“fooValue”和“barValue”,但Foo { fooValue = 42 }
中的冗余看起来也很尴尬。
这实际上是不同模块中更一般的函数问题的特殊情况,这些函数具有相同的名称但在不同的不相关类型上运行。不过,我似乎更频繁地使用字段名称。例如,我有几种数据类型,不是由类型类相关但经常一起使用,它们包含颜色值,所以我希望每个数据类型都有一个名为“color”的字段。
经验丰富的Haskell开发人员如何命名并将其组织成模块,以避免出现这种情况?
答案 0 :(得分:9)
GHC扩展程序-XDisambiguateRecordFields
将允许foo = Foo { value = 42 }
(但不允许n = value foo
)。
关于Haskell当前记录系统的缺点以及替代它的候选者,以及少数试图提供更好解决方案的库,有一个large body of literature。 fclabels
是我个人使用过的唯一一个。
This StackOverflow question类似,其中的一些答案也可能对您有用。
这是一个特例 更常见的功能问题 具有相同的不同模块 名称但操作不同, 不相关的类型。
Qualified imports和别名通常足以解决这个问题。
答案 1 :(得分:4)
经验丰富的Haskell开发人员如何命名并将其组织成模块,以避免出现这种情况?
我只与一些经验丰富的Haskell开发人员合作过,他们做了很多像
这样的事情data Foo a = Foo { foo_value :: a }
data Bar a = Bar { bar_value :: a }
甚至
data Apocalypse a = A { ap_value :: a }
总的来说,我觉得很多旧时候的Haskeller都不喜欢有资格的名字而且真的想假装这个世界只有一个大名鼎鼎的空间,直接走出黑暗时代。 (曾经有一段时间C编译器对字段名称有相同的限制,这就是为什么struct stat
中的模式被称为st_mode
而不仅仅是mode
。)
您可以使用类型类重载名称,但我知道的有经验的开发人员不喜欢免费类型类。当他们认为类型课程是无偿的时候,我永远无法弄明白。
我希望有一天Haskell人会接受一个分层名称空间并开始使用限定名称。按照上帝的意图。
答案 2 :(得分:1)
如果所有这些类型都有一个共同的访问器函数,您可以考虑一个类型类。 E.g。
class Fieldable a where
field :: a -> b
instance Fieldable (a,b) where
field = fst
等