避免Haskell中的命名空间污染

我在程序中使用了很多不同的logging,其中一些使用了相同的字段名称,例如

data Customer = Customer { ..., foo :: Int, ... } data Product = Product { ..., foo :: Int, ... } 

现在,由于访问函数“foo”被定义了两次,我得到了“多个声明”的错误。 避免这种情况的一种方法是使用导入完全限定的不同模块,或者只是重命名字段(我不想这样做)。

在Haskell中正式提出的处理方法是什么?

这是一个非常毛茸茸的问题。 有几个build议来修复logging系统。 相关说明见TDNR和咖啡馆相关讨论 。

使用当前可用的语言function,我认为最好的select是在两个不同的模块中定义两种types,并进行合格的导入。 最重要的是,如果你想,你可以实现一些types的机械。

在Customer.hs中

 module Customer where data Customer = Customer { ..., foo :: Int, ... } 

在Product.hs中

 module Product where data Product = Product { ..., foo :: Int, ... } 

在Third.hs中使用它们

 module Third where import qualified Customer as C import qualified Product as P .. C.foo .. .. P.foo .. 

但是,我想在你遇到recursion依赖模块的问题之前,不要太迟。

(仅供参考,这个问题几乎肯定是重复的)

解决scheme:

1)在字段前加一个表示types的标签(非常常见)

 data Customer = Customer {..., cFoo :: Int, ...} 

2)使用types类(不太常见,像cFoo这样的人抱怨前缀不方便,但显然没有那么糟糕,他们会写一个类和实例或使用TH做同样的)。

 class getFoo a where foo :: a -> Int instance getFoo Customer where foo = cFoo 

3)使用更好的字段名称如果字段实际上是不同的(这并不总是对的,我的电脑和我的员工一样有年龄),那么这是最好的解决scheme。

另请参阅Has软件包: http : //chrisdone.com/posts/duck-typing-in-haskell

如果你现在真的需要可扩展的logging,你总是可以使用HList。 但是我不会推荐这个,直到你对中级先进的Haskell非常熟悉和舒适,即使这样我也会三重检查你是否需要它。

Haskelldb有一个更轻量级的版本: http ://hackage.haskell.org/packages/archive/haskelldb/2.1.0/doc/html/Database-HaskellDB-HDBRec.html

然后有另一个版本的可扩展logging作为葡萄柚frp库的一部分: http : //hackage.haskell.org/package/grapefruit-records

再次,为了你的目的,我会咬子弹,只是重新命名的领域。 但是这些参考文献是要表明,当你真的需要可扩展logging的全部function时,有办法做到这一点,即使没有一个像精心devise的语言扩展那样愉快。

有一个语言扩展DuplicateRecordFields允许重复字段函数,并通过types注释来推断它的types。

这里有一个小例子( haskell-stack脚本):

 #!/usr/bin/env stack -- stack runghc --resolver lts-8.20 --install-ghc {-# LANGUAGE DuplicateRecordFields #-} newtype Foo = Foo { baz :: String } newtype Bar = Bar { baz :: String } foo = Foo { baz = "foo text" } bar = Bar { baz = "bar text" } main = do putStrLn $ "Foo: " ++ baz (foo :: Foo) -- Foo: foo text putStrLn $ "Bar: " ++ baz (bar :: Bar) -- Bar: bar text