有人可以解释关于`镜头`库的图表吗?

时间:2015-04-20 08:22:44

标签: haskell lens lenses

如果您浏览Lensage上的Lens条目,Lens Github的回购,甚至谷歌关于Lens,您会发现许多部分参考资料,例如介绍性教程/视频,示例,概述等。由于我已经了解了大部分基础知识,因此我正在寻找更完整的参考资料,以帮助我更多地了解高级功能。换句话说,我仍然不知道this意味着什么,并且找不到足够完整的资源来解释这个图形。想法?

2 个答案:

答案 0 :(得分:34)

黑线鳕是最好的深度资源。它们包含所有内容,但最初可能有点难以导航。只需浏览不同的模块,并记下哪些地方的心理记录,您很快就会找到自己的方式。您链接的图表也是模块的非常好的地图。

但是,既然您说您不了解图形,我会假设您不想要高级或完整的参考。该图实际上是lens包的各个部分的基本的高级概述。如果你不了解这个图表,你可能应该等一下高级的东西。

在阅读本文时,请记住,尽管lens封装最初是作为一个镜头包开始的,但现在包装中有多种光学,它们服从不同的法律,用于不同的事情。 "光学"是用于在数据结构上戳的类似镜头的东西的通用名称。

无论如何,这是我如何阅读图表。

The Boxes'装置

现在,只需查看写入光学元件名称的方框顶部。

  1. 顶级FoldSetterlens的基本光学元素。可以想象,Setter是一个设置某个字段值的光学元件。我会在这里省略一些例子,因为你说你知道大部分的基础知识,但基本上,当你做的时候

    λ> ellen & age .~ 35
    Person { _name = "Ellen", _age = 35 }
    

    然后您将age用作Setter

  2. Getter是一种特殊的Fold,它允许您从数据结构中获取值。 (Fold本身只允许您以某种方式将值组合到一个新值,而不是按原样将它们取出。)Getter是一种特殊的Fold标记在箭头指向GetterFold

  3. 如果你将FoldSetter结合起来(也就是说你结合了循环一堆值的方法和一种设置单个值的方法),你得到一个{{1} }。 Traversal是一个针对多个元素的光学元素,可让您设置或修改所有元素。

  4. 在图表的下方,如果您将TraversalGetter合并,则会获得Traversal。这应该是您所熟悉的,因为镜头通常被称为“吸气剂和定位器的组合”,您可以将Lens视为更强大的Traversal

  5. 我不会假装我对SetterReviewPrismIso之间的关系了解很多。我理解它的方式,

    • Equality是函数Review的基本包装,其中b -> t应该是b结构中的字段。因此t获取单个字段值,然后围绕它构造整个结构。这可能看起来很愚蠢,但它实际上与Review相反,对构建棱镜很有用。
    • Getter允许您在分支类型中获取和设置值。它是Prism Either对元组的意义。您只能通过镜头在Lens内获取值,因为如果它到达Either分支,它就会爆炸。
    • LeftIsoLens的强大组合,可让您自由地查看"两种方式"通过光学。虽然Prism允许您从高级别查看到数据结构的精确部分,但Lens还允许您从数据结构的精确部分查看到高级别。
    • Iso是......我不知道,抱歉。
  6. Interlude:Type Signatures

    类似Equality的类型签名一开始可能会让人感到恐惧,所以我会尝试快速涵盖它的含义。如果您查看Lens s t a b,您会看到其类型签名是

    Getter

    如果我们考虑概念上的吸气剂,这似乎很熟悉。什么是吸气剂?它是从数据结构Getter s a 到该结构内部的单个值s的函数。例如,函数a是一个从Person -> Age对象获取年龄的getter。相应的Person只有签名

    Getter

    真的那么简单。 Getter Person Age 是一种可以从Getter s a内获取a的视觉效果。

    简化的s签名现在应该不那么可怕了。如果你不得不猜测,那是什么

    Lens'

    ?简单!它是Lens' Person Age 可以获取并设置(还记得镜头是getter和setter的组合吗?)Lens字段中的Age字段。因此,您应用于Person的逻辑可以应用于Getter s a

    Lens' s a部分怎么样?好吧,想想这种类型:

    s t a b

    一个人可以通过某种识别价值识别并具有年龄。让我们说你是用名字

    来标识的
    data Person a = { _idField :: a, address :: String }
    

    如果您有一个函数carolyn :: Person String carolyn = Person "Carolyn" "North Street 12" 从字符串中生成ID号怎么办?你可能想这样做:

    toIdNumber :: String -> Int

    但是你可以λ> carolyn & idField %~ toIdNumber Person 57123 "North Street 12" ,因为那个镜头只能处理idField :: Lens' (Person String) String s。它不知道将字符串转换为整数并将其粘贴到同一位置意味着什么。这就是我们String

    的原因

    我读取签名的方式是#34;如果你给我一个函数Lens s t a b,我会给你一个函数a -> b",其中s -> t和{ {1}}都指向镜头的目标,ab指的是包含数据结构。具体例子:如果我们有

    s

    我们可以进行上面的转换。该镜头知道如何将带有字符串ID字段的t转换为具有idField :: Lens (Person String) (Person Int) String Int id字段的人。

    因此,基本上,Person可以被理解为"函数" Int。 "给我一个转换Lens s t a b来做我的目标,以及一个包含该目标的数据结构(a -> b) -> (s -> t),我将返回一个数据结构(a -> b),在那里进行转换已被应用。"

    当然,它实际上并不是那个功能 - 它比那更强大 - 但是你可以把它变成s,这是{{1}的一部分。 }}

    The Boxes'内容

    盒子的内容只是每种光学元件的最常见和/或核心操作。他们的类型很多地说明了他们做了什么,我会选择一些例子来说明我的意思。

    通常,最重要的项目是你如何构建这种光学元件。例如,t框中最顶部的项是over函数,它可以从任何函数Setter构造Getter。如果您使用to功能,则Getter免费获得s -> a

    然后在下面是常见的操作。您可以在Traversal下找到Traversable,这就是您使用traverse从数据结构中获取内容的方式。在view中,您会发现GetterGetter高位。

    (有趣的观察:大多数盒子似乎包含两个双重功能:一种创建光学器件的方法,以及一种使用它们的方法。有趣的是,那些通常具有几乎相同的类型签名,但翻转比较彼此。示例:

    • Setter
    • over

    • set
    • to :: (s -> a) -> Getter s a

    我现在注意到了一些有趣的东西。)

    我如何使用图形

    我通常不会像写这篇文章一样仔细研究图形。大多数情况下,我只是偷看view :: Getter s a -> (s -> a)unto :: (b -> t) -> Review s t a breview :: Review s t a b -> (b -> t)SetterGetter以及它们彼此之间的关系,因为那些是光学我用得最多。

    当我知道我需要做某事时,我通常会快速浏览一下图形,看看哪些框包含与我想要的操作类似的操作。 (例如,如果我有Traversal,则Lens与假设的Prism相似。)当我确定了这一点时,我会潜入Haddocks以获取这些模块(在这个例子,data Gendered a = Masculine a | Feminine a),搜索我需要的操作。

    我如何了解光学

    我学习光学以及如何使用它们的方式与学习一切相同。我发现一个真正的问题,光学是一个很好的解决方案,我试图解决它。我尝试了但是我失败了,我再试一次,我寻求帮助,我尝试尝试尝试。最终我会成功。然后我尝试了一些略有不同的东西。

    通过实际使用它们的方式,我会收集很多关于它们如何工作的有用经验。

    奖金:个人误解

    在我开始撰写本文之前,我认为您需要_Right来处理_Feminine值,因为Prism类型是分支,不是吗?不完全的!至少不超过Prism类型,您不需要Maybe来处理。

    因为Maybe类型是零个或一个元素的容器,所以实际上只需要一个List来处理它。当你有两个分支可以包含不同的值时,你需要Prism的全部功能。 (要构造 Maybe值,您仍然需要Traversal。)

    只有当我开始非常仔细地阅读图表并探索模块以找出光学系统之间的实际,形式差异时,我才想到这一点。这是使用我的方法来学习东西的缺点。只要它有效,我就是它。有时会导致迂回的做事方式。

答案 1 :(得分:1)

图形是两种类型之间弱关系所能做的事情,以及强关系所能做的事情。

在最弱的情况下,您可以在a类型中折叠s类型的“元素”,或者可以在a内将b设置为s {1}},将其更改为tab当然可以与st相同。在最底层,你有平等;一步,你有同构;镜头和棱镜等

从另一个角度来看,由于关系的要求,它从最适用的流向最不适用:有许多类型可以在概念上“折叠”在某些a之内。然而,与a相比,更少的东西将是平等的或同构的。