gpt4 book ai didi

data-structures - 镜头、fclabels、数据访问器——哪个库用于结构访问和变异更好

转载 作者:行者123 更新时间:2023-12-03 04:17:04 27 4
gpt4 key购买 nike

至少有三个流行的库用于访问和操作记录字段。我所知道的有:数据访问器、fclabels 和镜头。

我个人从数据访问器开始,现在正在使用它们。然而,最近在 haskell-cafe 上,有人认为 fclabels 更胜一筹。

因此,我对这三个(也许更多)库的比较感兴趣。

最佳答案

我知道至少有 4 个库提供镜头。

镜头的概念是它提供了一些同构的东西

data Lens a b = Lens (a -> b) (b -> a -> a)

提供两个函数:getter 和 setter
get (Lens g _) = g
put (Lens _ s) = s

受三项法律约束:

首先,如果你放了东西,你可以把它拿回来
get l (put l b a) = b 

其次,获取然后设置不会改变答案
put l (get l a) a = a

第三,两次推杆与一次推杆相同,或者更确切地说,第二次推杆获胜。
put l b1 (put l b2 a) = put l b1 a

请注意,类型系统不足以为您检查这些法律,因此无论您使用何种镜头实现,您都需要自己确保它们。

这些库中的许多还在顶部提供了一堆额外的组合器,通常是某种形式的模板 haskell 机制来自动为简单记录类型的字段生成镜头。

考虑到这一点,我们可以转向不同的实现:

实现

fclabels

fclabels可能是最容易推理的镜头库,因为它的 a :-> b可以直接翻译成上述类型。它提供了一个 Category (:->) 的实例这很有用,因为它允许您组合镜头。它还提供了一个无法无天的 Point type 概括了这里使用的镜头的概念,以及一些处理同构的管道。

采用 fclabels 的一个障碍是主包包括模板-haskell 管道,所以包不是 Haskell 98,它还需要(相当无争议) TypeOperators扩展名。

数据访问器

[编辑: data-accessor不再使用这种表示形式,而是转为类似于 data-lens 的形式。 .不过,我保留这个评论。]

data-accessorfclabels 更受欢迎,部分是因为它是 Haskell 98。然而,它对内部表示的选择让我有点吐槽。

型号 T它用来表示一个镜头在内部定义为
newtype T r a = Cons { decons :: a -> r -> (a, r) }

因此,为了 get镜头的值,您必须为“a”参数提交一个未定义的值!这让我觉得这是一个非常丑陋和临时的实现。

也就是说,Henning 已经包含了模板-haskell 管道,可以在单独的“ data-accessor-template”中为您自动生成访问器。 ' 包。

它具有大量已经使用它的软件包的好处,即 Haskell 98,并提供了最重要的 Category比如,如果你不注意香肠是如何制作的,这个包实际上是很合理的选择。

镜片

接下来是 lenses包,它观察到一个镜头可以在两个状态 monad 之间提供一个状态 monad 同态,通过直接将镜头定义为这样的 monad 同态。

如果它真的很费心为其镜头提供一种类型,那么它们将具有 2 级类型,例如:
newtype Lens s t = Lens (forall a. State t a -> State s a)

因此,我宁愿不喜欢这种方法,因为它不必要地将您从 Haskell 98 中拉出来(如果您想抽象地为您的镜头提供一种类型)并剥夺您的 Category例如镜头,它可以让你用 . 组合它们.该实现还需要多参数类型类。

请注意,此处提到的所有其他镜头库都提供了一些组合器,或者可用于提供相同的状态聚焦效果,因此以这种方式直接对镜头进行编码没有任何好处。

此外,开头所述的附带条件在这种形式中并没有很好的表达。与“fclabels”一样,这确实提供了模板-haskell 方法,用于直接在主包中为记录类型自动生成镜头。

因为缺少 Category例如,巴洛克式编码,以及 main 包中的 template-haskell 要求,这是我最不喜欢的实现。

数据镜头

[编辑:从 1.8.0 开始,这些已经从 comonad-transformers 包转移到数据镜头]

我的 data-lens 套餐提供镜头方面的 Store共和。
newtype Lens a b = Lens (a -> Store b a)

在哪里
data Store b a = Store (b -> a) b

展开这相当于
newtype Lens a b = Lens (a -> (b, b -> a))

您可以将其视为从 getter 和 setter 中分解出公共(public)参数以返回由检索元素的结果和一个将新值放入其中的 setter 组成的对。这提供了“setter”的计算优势这里可以回收一些用于获取值的工作,从而使“修改”操作比 fclabels 中的操作更有效。定义,尤其是当访问器被链接时。

这种表示还有一个很好的理论依据,因为满足此响应开头所述的 3 条定律的“镜头”值的子集恰好是那些包装函数是商店 comonad 的“comonad 代数”的那些镜头.这改变了镜头的 3 条毛规律 l下降到 2 个很好的 pointfree 等价物:
extract . l = id
duplicate . l = fmap l . l

在 Russell O'Connor 的 Functor is to Lens as Applicative is to Biplate : Introducing Multiplate 中首次注意到并描述了这种方法。并且是 blogged about based on a preprint通过杰里米吉本斯。

它还包括许多用于严格处理镜头的组合器和一些用于容器的库存镜头,例如 Data.Map .

所以 data-lens中的镜片形成 Category (与 lenses 包不同),是 Haskell 98(与 fclabels/ lenses 不同),是理智的(与 data-accessor 的后端不同)并提供稍微更有效的实现, data-lens-fd 为那些愿意走出 Haskell 98 的人提供使用 MonadState 的功能,现在可以通过 data-lens-template 获得模板-haskell 机制。 .

2012 年 6 月 28 日更新:其他镜头实现策略

同构镜片

还有另外两种镜头编码值得考虑。第一个给出了一种很好的理论方法,可以将镜头视为将结构分解为场值和“其他一切”的一种方式。

给定同构的类型
data Iso a b = Iso { hither :: a -> b, yon :: b -> a }

使得有效成员满足 hither . yon = id , 和 yon . hither = id
我们可以表示一个镜头:
data Lens a b = forall c. Lens (Iso a (b,c))

这些主要用作思考镜头含义的一种方式,我们可以将它们用作解释其他镜头的推理工具。

van Laarhoven 镜片

我们可以对镜头进行建模,以便它们可以与 (.) 组合在一起。和 id ,即使没有 Category使用实例
type Lens a b = forall f. Functor f => (b -> f b) -> a -> f a

作为我们镜头的类型。

那么定义一个镜头就像这样简单:
_2 f (a,b) = (,) a <$> f b

您可以自己验证功能组合是镜头组合。

我最近写了一篇关于如何进一步发展的文章 generalize van Laarhoven lenses获得可以改变场类型的镜头系列,只需将此签名推广到
type LensFamily a b c d = forall f. Functor f => (c -> f d) -> a -> f b

这确实有一个不幸的后果,即谈论镜头的最佳方式是使用 2 级多态性,但在定义镜头时不需要直接使用该签名。
Lens我在上面定义了 _2实际上是 LensFamily .
_2 :: Functor f => (a -> f b) -> (c,a) -> f (c, b)

我编写了一个库,其中包括镜头、镜头系列和其他概括,包括 getter、setter、折叠和遍历。它在 hackage 上可用,名称为 lens 包裹。

同样,这种方法的一大优势是库维护者实际上可以在您的库中创建这种风格的镜头,而不会产生任何镜头库依赖性,只需提供类型为 Functor f => (b -> f b) -> a -> f a 的函数即可。 , 对于它们的特定类型 'a' 和 'b'。这大大降低了采用成本。

由于您不需要实际使用该包来定义新镜头,因此我之前对保留 Haskell 98 库的担忧减轻了很多压力。

关于data-structures - 镜头、fclabels、数据访问器——哪个库用于结构访问和变异更好,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5767129/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com