简体   繁体   English

Haskell记录中的名称冲突

[英]Name conflicts in Haskell records

Haskell doesn't have dot notation for record members. Haskell没有记录成员的点符号。 For each record member a compiler creates a function with the same name with a type RecType -> FieldType. 对于每个记录成员,编译器使用RecType - > FieldType类型创建具有相同名称的函数。 This leads to name conflicts. 这会导致名称冲突。 Are there any ways to work around this, ie how can I have several records with the same field names? 有没有办法解决这个问题,即如何拥有多个具有相同字段名称的记录?

For large projects, I prefer to keep each type in its own module and use Haskell's module system to namespace accessors for each type. 对于大型项目,我更喜欢将每种类型保留在自己的模块中,并使用Haskell的模块系统来为每种类型命名空间访问器。

For example, I might have some type A in module A : 例如,我可能有一些类型的A模块A

-- A.hs

data A = A
    { field1 :: String
    , field2 :: Double
    }

... and another type B with similarly-named fields in module B : ......和另一种类型的B与模块类似命名的字段B

-- B.hs

data B = B
    { field1 :: Char
    , field2 :: Int
    }

Then if I want to use both types in some other module C I can import them qualified to distinguish which accessor I mean: 然后,如果我想在其他模块C使用这两种类型,我可以导入它们,以区分我的意思是:

-- C.hs
import A as A
import B as B

f :: A -> B -> (Double, Int)
f a b = (A.field2 a, B.field2 b)

Unfortunately, Haskell does not have a way to define multiple name-spaces within the same module, otherwise there would be no need to split each type in a separate module to do this. 不幸的是,Haskell没有办法在同一个模块中定义多个名称空间,否则就不需要在单独的模块中拆分每个类型来执行此操作。

Another way to avoid this problem is to use the lens package. 避免此问题的另一种方法是使用镜头包装。 It provides a makeFields template haskell function, which you can use like this: 它提供了一个makeFields模板haskell函数,你可以这样使用:

{-# LANGUAGE FlexibleInstances      #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses  #-}
{-# LANGUAGE TemplateHaskell        #-}
{-# LANGUAGE TypeSynonymInstances   #-}
import           Control.Lens

data A = A
  { _aText :: String
  }
makeFields ''A   -- Creates a lens x for each record accessor with the name _aX

data B = B
  { _bText  :: Int
  , _bValue :: Int
  }
-- Creates a lens x for each record accessor with the name _bX
makeFields ''B  

main = do
  let a = A "hello"
  let b = B 42 1

  -- (^.) is a function of lens which accesses a field (text) of some value (a)
  putStrLn $ "Text of a: " ++ a ^. text 
  putStrLn $ "Text of b: " ++ show (b ^. text)

If you don't want to use TemplateHaskell and lens, you can also do manually what lens automates using TemplateHaskell: 如果您不想使用TemplateHaskell和镜头,您也可以手动使用TemplateHaskell自动执行哪些镜头:

{-# LANGUAGE FlexibleInstances      #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses  #-}
{-# LANGUAGE TypeSynonymInstances   #-}
data A = A
  { aText :: String
  }

data B = B
  { bText  :: Int
  , bValue :: Int
  }

-- A class for types a that have a "text" field of type t
class HasText a t | a -> t where

  -- An accessor for the text value
  text :: a -> t

-- Make our two types instances of those
instance HasText A String where text = aText
instance HasText B Int where text = bText

main = do
  let a = A "hello"
  let b = B 42 1
  putStrLn $ "Text of a: " ++ text a
  putStrLn $ "Text of b: " ++ show (text b)

But I can really recommend learning lens, as it also provides lots of other utilities, like modifying or setting a field. 但我真的可以推荐学习镜头,因为它还提供了许多其他工具,例如修改或设置字段。

The GHC developers developed a couple of extensions to help with this issue . GHC开发人员开发了几个扩展来帮助解决这个问题。 Check out this ghc wiki page . 看看这个ghc wiki页面 Initially a single OverloadedRecordFields extension was planned, but instead two extensions were developed. 最初计划了一个OverloadedRecordFields扩展,但是开发了两个扩展。 The extensions are OverloadedLabels and DuplicateRecordFields . 扩展名为OverloadedLabelsDuplicateRecordFields Also see that reddit discussion . 另见reddit讨论

The DuplicateRecordFields extensions makes this code legal in a single module: DuplicateRecordFields扩展使得此代码在单个模块中合法:

data Person  = MkPerson  { personId :: Int, name :: String }
data Address = MkAddress { personId :: Int, address :: String }

As of 2019, I'd say these two extensions didn't get the adoption I thought they would have (although they did get some adoption) and the status quo is probably still ongoing. 截至2019年,我认为这两个扩展没有得到我认为他们会有的采用(虽然他们确实得到了一些采用)并且现状可能仍在继续。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM