Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/visual-studio-2010/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 什么';MakeLens和makeFields之间的区别是什么?_Haskell_Haskell Lens - Fatal编程技术网

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
    成为该类的一个实例
注意:此答案基于lens 4.4或更新版本。那个版本的TH有一些变化,所以我不知道有多少适用于旧版本的镜头

职能的组织 镜头TH功能都基于一个功能,
makeLensesWith
(也称为
makeFieldOptics
镜头内部)。此函数采用
LensRules
参数,该参数准确描述生成的内容和方式

因此,要比较
makelens
makeFields
,我们只需要比较它们使用的
LensRules
。您可以通过查看以下内容找到它们:

制造透镜 马克菲尔德 这些是什么意思? 现在我们知道,区别在于
simpleLenses
generateClasses
allowIsos
fieldToDef
选项。但这些选择究竟意味着什么

  • makeFields
    永远不会生成类型更改光学元件。这由
    simpleLenses=True
    选项控制。该选项在当前版本的lens中没有haddocks。但是,lens HEAD为其添加了文档:

     -- | 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