很不言自明。我知道makeClassy
应该创建类型类,但我认为两者之间没有区别。
PS。解释两者的默认行为的奖励积分。
最佳答案
注意:此答案基于镜头 4.4 或更高版本。那个版本的 TH 有一些变化,所以我不知道它有多少适用于旧版本的镜头。
镜头 TH 功能的组织
镜头 TH 函数都基于一个函数 makeLensesWith
(也称为 makeFieldOptics
内部镜头)。这个函数需要一个 LensRules
参数,它准确地描述了生成什么以及如何生成。
所以比较makeLenses
和 makeFields
,我们只需要比较LensRules
他们使用的。您可以通过查看 source 找到它们。 :
制作镜头
lensRules :: LensRules
lensRules = LensRules
{ _simpleLenses = False
, _generateSigs = True
, _generateClasses = False
, _allowIsos = True
, _classyLenses = const Nothing
, _fieldToDef = \_ n ->
case nameBase n of
'_':x:xs -> [TopName (mkName (toLower x:xs))]
_ -> []
}
生成字段
defaultFieldRules :: LensRules
defaultFieldRules = LensRules
{ _simpleLenses = True
, _generateSigs = True
, _generateClasses = True -- classes will still be skipped if they already exist
, _allowIsos = False -- generating Isos would hinder field class reuse
, _classyLenses = const Nothing
, _fieldToDef = camelCaseNamer
}
这些是什么意思?
现在我们知道不同之处在于
simpleLenses
, generateClasses
, allowIsos
和 fieldToDef
选项。但这些选项实际上意味着什么?makeFields
永远不会产生改变类型的光学元件。这由 simpleLenses = True
控制。选项。该选项在当前版本的镜头中没有黑线鳕。但是,lens HEAD 为其添加了文档: -- | Generate "simple" optics even when type-changing optics are possible.
-- (e.g. 'Lens'' instead of 'Lens')
所以
makeFields
makeLenses
永远不会产生类型改变的光学元件如果可能的话。 makeFields
将为字段生成类。所以对于每个字段 foo
,我们有一个类:class HasFoo t where
foo :: Lens' t <Type of foo field>
这由
generateClasses
控制。选项。 makeFields
永远不会生成 Iso
的,即使这是可能的(由 allowIsos
选项控制,它似乎不是从 Control.Lens.TH
导出的)makeLenses
只需为以下划线开头的每个字段生成一个顶级镜头(下划线后的第一个字母小写),makeFields
而是为 HasFoo
生成实例类。它还使用了不同的命名方案,在源代码的注释中进行了解释:-- | Field rules for fields in the form @ prefixFieldname or _prefixFieldname @
-- If you want all fields to be lensed, then there is no reason to use an @_@ before the prefix.
-- If any of the record fields leads with an @_@ then it is assume a field without an @_@ should not have a lens created.
camelCaseFields :: LensRules
camelCaseFields = defaultFieldRules
所以
makeFields
还期望所有字段不仅带有下划线前缀,而且还包括数据类型名称作为前缀(如 data Foo = { _fooBar :: Int, _fooBaz :: Bool }
中)。如果要为所有领域生成镜头,可以省略下划线。这一切都由
_fieldToDef
控制。 (由 lensField
导出为 Control.Lens.TH
)。 如您所见,
Control.Lens.TH
模块非常灵活。使用 makeLensesWith
,您可以创建自己的LensRules
如果您需要标准功能未涵盖的模式。
关于haskell - makeLenses 和 makeFields 有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25585650/