我使用许多不同的记录程序,其中一些使用相同的字段名称,例如
data Customer = Customer { ..., foo :: Int, ... }
data Product = Product { ..., foo :: Int, ... }
现在,作为存取“foo”函数被定义了两次,我得到了“多次声明”的错误。为了避免这种情况的一个方法是使用进口的完全限定不同的模块,或者干脆重命名字段(我不想做)。
什么是正式提出这个在Haskell处理方式?
这是一个非常毛茸茸的问题。有固定的备案制度若干建议。在一个相关的说明,请参阅TDNR和related discussion on cafe。
利用当前可用的语言特性,我认为最好的办法是在定义两个不同的模块中的两种类型,做一个合格的进口。在此之上,如果你愿意,你也可以实现某些类型的类机械。
在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 ..
然而,我想它会不会太晚了,你撞一下recursively dependent modules问题之前。
(仅供参考,这个问题几乎可以肯定是重复的)
解决方案:
1)前缀字段具有指示类型标签(极为常见)
data Customer = Customer {..., cFoo :: Int, ...}
2)使用类型类(较少见,有人抱怨像cFoo
前缀是不方便,但显然并没有那么糟糕,他们会写一个类和实例或使用TH这样做)。
class getFoo a where
foo :: a -> Int
instance getFoo Customer where
foo = cFoo
3)使用更好的字段名。如果场实际上是不同的(这并不总是正确的,我的电脑有一样我的员工的年龄),那么这是最好的解决办法。
又见有包: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
同样,你的目的,我硬着头皮只是重命名字段。但是,这些提法表明,当你真正需要的可扩展记录的全部力量,有办法做到这一点,即使没有一个是愉快的一个精心设计的语言扩展会。
有一个语言扩展DuplicateRecordFields
允许的领域职能重叠,使公司类型由类型注释来推断。
这里是一个小例子(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
一个可能的解决方案,这将使你的代码更简洁的定义<.>
为:
(<.>) :: (Emiter e1, Emiter e2) => e1 -> e2 -> String
lhs <.> rhs = emit lhs <> emit rhs
然后发射器可以是这样的:
class Emiter n where
emit :: n -> String
instance Emiter String where
emit = id
instance Emiter A where
emit A {
foo = foo'
bar = bar'
} = foo' <.> "--" <.> bar'
instance Emiter B where
emit B {
foo = foo'
bar = bar'
} = "[" <.> bar' <.> foo' <.> "]"