Haskell记录中的名称冲突

时间:2013-07-04 22:00:44

标签: haskell

Haskell没有记录成员的点表示法。对于每个记录成员,编译器创建一个具有相同名称的函数,其类型为RecType - >的FieldType。这会导致名称冲突。有没有办法解决这个问题,即我怎么能有几个具有相同字段名称的记录?

3 个答案:

答案 0 :(得分:19)

对于大型项目,我更喜欢将每种类型保留在自己的模块中,并使用Haskell的模块系统来为每种类型命名空间访问器。

例如,我可能在模块A中有一些类型A

-- A.hs

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

...以及模块B中具有类似命名字段的另一种类型B

-- B.hs

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

然后,如果我想在其他模块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)

不幸的是,Haskell无法在同一个模块中定义多个名称空间,否则需要在单独的模块中拆分每个类型才能执行此操作。

答案 1 :(得分:17)

避免此问题的另一种方法是使用lens包。它提供了一个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)

如果你不想使用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)

但我真的可以推荐学习镜头,因为它还提供了许多其他工具,例如修改或设置字段。

答案 2 :(得分:6)

请注意,GHC开发人员似乎计划在未来如何处理此问题。查看我在this plan末尾提到的this blog post