避免 Haskell 中的名称空间污染
我在程序中使用许多不同的记录,其中一些使用相同的字段名称,例如,
data Customer = Customer { ..., foo :: Int, ... }
data Product = Product { ..., foo :: Int, ... }
现在由于访问器函数“foo”被定义了两次,我收到“多重声明”错误。避免这种情况的一种方法是使用完全限定导入的不同模块,或者简单地重命名字段(我不想这样做)。
Haskell 中处理此问题的官方建议方法是什么?
I'm using lots of different records in a program, with some of them using the same field names, e.g.
data Customer = Customer { ..., foo :: Int, ... }
data Product = Product { ..., foo :: Int, ... }
Now as the accessor function "foo" is defined twice, I get the "Multiple declarations" error. One way to avoid this would be using different modules that are imported fully qualified, or simply renaming the fields (which I don't want to do).
What is the officially suggested way of dealing with this in Haskell?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
这是一个非常棘手的问题。有几个修复记录系统的建议。有关相关说明,请参阅 TDNR 和 cafe 相关讨论.
使用当前可用的语言功能,我认为最好的选择是在两个不同的模块中定义两种类型,并进行合格的导入。除此之外,如果您愿意,您可以实现一些类型类机制。
在 Customer.hs
在 Product.hs
在使用它们时,在 Third.hs
然而,我想在您遇到有关 递归依赖模块。
This is a very hairy problem. There are several proposals for fixing the record system. On a related note, see TDNR and related discussion on cafe.
Using the currently available language features, I think the best option is defining the two types in two different modules, and doing a qualified import. On top of this, if you want, you can implement some type class machinery.
In Customer.hs
In Product.hs
While using them, in Third.hs
Yet, I imagine it won't be too late before you hit the problem about recursively dependent modules.
(仅供参考,这个问题几乎肯定是重复的)
解决方案:
1)在字段前添加一个指示类型的标签前缀(非常常见)
2)使用类型类(不太常见,人们抱怨像
cFoo
这样的前缀是不方便,但显然还不错,他们会编写一个类和实例,或者使用 TH 来做同样的事情)。3)使用更好的字段名称
如果这些字段实际上不同(这并不总是正确的,我的计算机和我的员工一样都有年龄),那么这是最好的解决方案。
(FYI, this question is almost certainly a duplicate)
Solutions:
1) Prefix the fields with a tag indicating the type (extremely common)
2) Use type classes (less common, people complain prefixes like
cFoo
are inconvenient but evidently not so bad that they will write a class and instance or use TH to do the same).3) Use better field names
If the fields are actually different (which isn't always true, my computer has an age as does my employee), then this is the best solution.
有一个语言扩展
DuplicateRecordFields
,它允许复制字段函数并使其类型可以通过类型注释来推断。这是一个小例子(haskell-stack 脚本):
There's a language extension
DuplicateRecordFields
that allows duplication of field functions and makes its type to be inferred by type annotation.Here is a little example (haskell-stack script):
另请参阅 Has 包: http://chrisdone.com/posts/duck-typing- in-haskell
如果您现在确实需要可扩展记录,则可以随时使用 HList。但在你真正熟悉并熟悉中高级 Haskell 之前我不会推荐这个,即使这样我也会三重检查你是否需要它。
Haskelldb 有一个稍微轻量级的版本: http://hackage.haskell.org/packages/archive/haskelldb/2.1.0/doc/html/Database-HaskellDB-HDBRec.html
然后还有另一个版本的可扩展记录作为柚子的一部分frp 库: http://hackage.haskell.org/package/grapefruit-records
再次,为了您的目的,我会硬着头皮重命名字段。但这些参考资料表明,当您确实需要可扩展记录的全部功能时,有很多方法可以做到这一点,即使没有一种方法像精心设计的语言扩展那样令人愉快。
See also the Has package: http://chrisdone.com/posts/duck-typing-in-haskell
And if you really need extensible records now, you can always use HList. But I wouldn't recommend this until you're really familiar and comfortable with medium-advanced Haskell, and even then I'd triple check you need it.
Haskelldb has a slightly more lightweight version: http://hackage.haskell.org/packages/archive/haskelldb/2.1.0/doc/html/Database-HaskellDB-HDBRec.html
And then there's another version of extensible records as part of the grapefruit frp library: http://hackage.haskell.org/package/grapefruit-records
Again, for your purposes, I'd bite the bullet and just rename the fields. But these references are to show that when you really need the full power of extensible records, there are ways to do it, even if none are as pleasant as a well-designed language extension would be.
一种可能的解决方案是,将
<.>
定义为:那么发射器可以如下所示:
One possible solution that will make your code less verbose is to define
<.>
as:Then emitters can look like: