我有两种数据类型,用于hastache模板.在我的代码中有两种不同的类型是有意义的,都有一个名为"name"的字段.当然,这会引发冲突.似乎有一种机制可以消除对"name"的任何调用的歧义,但实际的定义会导致问题.是否有任何解决方法,比如让记录字段名称合格?
data DeviceArray = DeviceArray
{ name :: String,
bytes :: Int }
deriving (Eq, Show, Data, Typeable)
data TemplateParams = TemplateParams
{ arrays :: [DeviceArray],
input :: DeviceArray }
deriving (Eq, Show, Data, Typeable)
data MakefileParams = MakefileParams
{ name :: String }
deriving (Eq, Show, Data, Typeable)
Run Code Online (Sandbox Code Playgroud)
即如果字段现在在代码中使用,它们将是"DeviceArray.name"和"MakefileParams.name"?
C. *_*ann 12
正如已经指出的那样,这不是直接可行的,但我想谈谈提议的解决方案:
如果两个字段明显不同,那么您将始终知道您正在使用哪个字段.在这里,"明显不同",我的意思是,永远不会有任何情况,在任何一个领域做同样的事情是有意义的.鉴于此,过度的歧义并非真正不受欢迎,因此您需要合格的导入作为标准方法,或者如果更符合您的口味,则需要字段消歧扩展.或者,作为一个非常简单(并且稍微丑陋)的选项,只需手动为字段添加前缀,例如deviceArrayName而不是仅仅name.
如果这两个领域在某种意义上是相同的,那么能够以同质的方式对待它们是有意义的; 理想情况下,您可以在name字段选择中编写函数多态.在这种情况下,一个选项是使用类型类来"命名事物",其中的函数允许您name以任何适当的类型访问该字段.这里的一个主要缺点是,除了普通类型约束的增加以及可怕的单形态限制可能带来的麻烦之外,你也失去了使用记录语法的能力,这开始打败了整个点.
我没有看到的类似字段的另一个主要选项是将name字段提取为单个参数化类型,例如data Named a = Named { name :: String, item :: a }.GHC本身将这种方法用于语法树中的源位置,虽然它不使用记录语法,但这个想法是相同的.这里的缺点是,如果你有一个Named DeviceArray,访问该bytes字段现在需要通过两层记录.如果你想bytes用一个函数更新字段,你会遇到这样的事情:
addBytes b na = na { item = (item na) { bytes = b + bytes (item na) } }
Run Code Online (Sandbox Code Playgroud)
啊.有一些方法可以缓解这个问题,但在我看来,它们仍然不是主意.像这样的情况是我不喜欢一般记录语法的原因.所以,作为最后的选择,一些模板哈斯克尔魔术和的fclabels包:
{-# LANGUAGE TemplateHaskell #-}
import Control.Category
import Data.Record.Label
data Named a = Named
{ _name :: String,
_namedItem :: a }
deriving (Eq, Show, Data, Typeable)
data DeviceArray = DeviceArray { _bytes :: Int }
deriving (Eq, Show, Data, Typeable)
data MakefileParams = MakefileParams { _makefileParams :: [MakeParam] }
deriving (Eq, Show, Data, Typeable)
data MakeParam = MakeParam { paramText :: String }
deriving (Eq, Show, Data, Typeable)
$(mkLabels [''Named, ''DeviceArray, ''MakefileParams, ''MakeParam])
Run Code Online (Sandbox Code Playgroud)
不介意MakeParam做生意,我只需要在那里做一些事情.无论如何,现在你可以修改这样的字段:
addBytes b = modL (namedItem >>> bytes) (b +)
nubParams = modL (namedItem >>> makefileParams) nub
Run Code Online (Sandbox Code Playgroud)
您也可以将其命名bytes类似bytesInternal,然后导出的访问bytes = namedItem >>> bytesInternal,如果你喜欢.
记录字段名称与数据类型在同一范围内,因此您无法直接执行此操作.
解决这种情况的常用方法是,要么添加前缀字段名称,例如daName,mpName或者把它们放在单独的模块,你然后import qualified.