Haskell 什么';MakeLens和makeFields之间的区别是什么?
非常不言自明。我知道Haskell 什么';MakeLens和makeFields之间的区别是什么?,haskell,haskell-lens,Haskell,Haskell Lens,非常不言自明。我知道makeClassy应该创建类型类,但我看不出两者之间有什么区别 PS.解释两者默认行为的额外点数。免责声明:这是基于对工作代码的实验;它给了我足够的信息来继续我的项目,但我还是希望有一个更好的书面答案 makelens 将创建foo作为Stuff 将创建fooBar(将大写名称更改为小写) makeFields 将创建baz和类HasBaz;它将使Stuff成为该类的一个实例 注意:此答案基于lens 4.4或更新版本。那个版本的TH有一些变化,所以我不知道有多少适用
makeClassy
应该创建类型类,但我看不出两者之间有什么区别
PS.解释两者默认行为的额外点数。免责声明:这是基于对工作代码的实验;它给了我足够的信息来继续我的项目,但我还是希望有一个更好的书面答案
makelens
- 将创建
作为foo
Stuff
- 将创建
(将大写名称更改为小写)李>fooBar
makeFields
- 将创建
和类baz
;它将使HasBaz
成为该类的一个实例Stuff
makeLensesWith
(也称为makeFieldOptics
镜头内部)。此函数采用LensRules
参数,该参数准确描述生成的内容和方式
因此,要比较makelens
和makeFields
,我们只需要比较它们使用的LensRules
。您可以通过查看以下内容找到它们:
制造透镜
马克菲尔德
这些是什么意思?
现在我们知道,区别在于simpleLenses
、generateClasses
、allowIsos
和fieldToDef
选项。但这些选择究竟意味着什么
永远不会生成类型更改光学元件。这由makeFields
选项控制。该选项在当前版本的lens中没有haddocks。但是,lens HEAD为其添加了文档:simpleLenses=True
因此,-- | Generate "simple" optics even when type-changing optics are possible. -- (e.g. 'Lens'' instead of 'Lens')
将永远不会生成类型更改光学元件,而makeFields
将尽可能生成类型更改光学元件makelens
将为字段生成类。因此,对于每个字段makeFields
,我们有一个类:foo
因此,class HasFoo t where foo :: Lens' t <Type of foo field>
也期望所有字段不仅仅以下划线作为前缀,还包括数据类型名称作为前缀(如makeFields
)。如果要为所有字段生成镜头,可以省去下划线 这一切都由data Foo={{u fooBar::Int,_fooBaz::Bool}
控制(通过\u fieldToDef
导出为Control.Lens.TH
)lensField
Control.Lens.TH
模块非常灵活。使用makeLensesWith
,如果需要标准函数未包含的模式,您可以创建自己的LensRules
。Normal
MakeLens
为类型中的每个字段创建一个顶级光学元件。它查找以下划线(\uu
)开头的字段,并创建一个尽可能通用的字段
- 如果您的类型有一个构造函数和一个字段,您将得到一个
Iso
- 如果你的类型有一个构造函数和多个字段,你会得到很多
镜头
- 如果您的类型有多个构造函数,您将获得许多
遍历
makeClassy
创建一个类,其中包含您类型的所有光学元件。此版本用于轻松地将您的类型嵌入到另一个更大的类型中,从而实现一种子类型<代码>镜头和遍历
光学元件将根据上述规则创建(Iso
被排除在外,因为它阻碍了子类型行为。)
除了每个字段类中的一个方法之外,您还将获得一个额外的方法,该方法可以轻松地为其他类型派生此类的实例。就顶级方法而言,所有其他方法都有默认实例
data T = MkT { _field1 :: Int, _field2 :: Char }
class HasT a where
t :: Lens' a T
field1 :: Lens' a Int
field2 :: Lens' a Char
field1 = t . field1
field2 = t . field2
instance HasT T where
t = id
field1 f (MkT x y) = fmap (\x' -> MkT x' y) (f x)
field2 f (MkT x y) = fmap (\y' -> MkT x y') (f y)
data U = MkU { _subt :: T, _field3 :: Bool }
instance HasT U where
t f (MkU x y) = fmap (\x' -> MkU x' y) (f x)
-- field1 and field2 automatically defined
这样做的另一个好处是,可以轻松导出/导入给定类型的所有镜头<代码>导入模块(HasT(..)
领域
makeFields
为每个字段创建一个类,以便在具有给定名称的字段的所有类型之间重用。这更像是一种解决方案,用于记录无法在类型之间共享的字段名。我想可能会回答这个问题,因为字段
创建了基于名称的类,而镜头
没有,但我不知道如何验证这一点。
-- | Generate "simple" optics even when type-changing optics are possible.
-- (e.g. 'Lens'' instead of 'Lens')
class HasFoo t where
foo :: Lens' t <Type of foo field>
-- | 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
data T = MkT { _field1 :: Int, _field2 :: Char }
class HasT a where
t :: Lens' a T
field1 :: Lens' a Int
field2 :: Lens' a Char
field1 = t . field1
field2 = t . field2
instance HasT T where
t = id
field1 f (MkT x y) = fmap (\x' -> MkT x' y) (f x)
field2 f (MkT x y) = fmap (\y' -> MkT x y') (f y)
data U = MkU { _subt :: T, _field3 :: Bool }
instance HasT U where
t f (MkU x y) = fmap (\x' -> MkU x' y) (f x)
-- field1 and field2 automatically defined