镜片

什么是镜头?

镜头(和其他光学)让我们分开描述如何,我们想从访问某些数据是什么,我们想用它做。区分镜头的抽象概念和具体实现是很重要的。从长远来看,抽象地理解使用 lens 进行编程变得更容易。镜头有许多同构表示,因此在本次讨论中,我们将避免任何具体的实现讨论,而是对概念进行高级概述。

调焦

抽象理解的一个重要概念是聚焦的概念。重要的光学器件专注于更大数据结构的特定部分,而不会忘记更大的背景。例如,镜头 _1 专注于元组的第一个元素,但不会忘记第二个字段中的内容。

一旦我们有了焦点,我们就可以谈谈我们允许用镜头执行哪些操作。鉴于 Lens s a,当给定 s 类型的数据类型时,我们可以关注特定的 a,我们可以

  1. 通过忘记附加的上下文或提取 a
  2. 通过提供新值来替换 a

这些对应于众所周知的 getset 操作,这些操作通常用于表征镜头。

其他光学

我们可以用类似的方式谈论其他光学器件。

光纤 专注于…
镜片 产品的一部分
棱镜 一部分金额
穿越 数据结构的零个或多个部分
同构

每个光学元件以不同的方式聚焦,因此,根据我们具有的光学器件类型,我们可以执行不同的操作。

组成

更重要的是,我们可以组合我们迄今为止所讨论的两种光学器件中的任何一种,以指定复杂的数据访问。我们讨论过的四种光学元件形成一个晶格,将两个光学元件组合在一起的结果就是它们的上界。

StackOverflow 文档

例如,如果我们将镜头和棱镜组合在一起,我们就会进行遍历。其原因在于,通过它们(垂直)的构图,我们首先关注产品的一部分,然后关注一部分的总和。结果是一个光学器件,它专注于我们数据的精确零点或一部分,这是一个特殊的遍历情况。 (这有时也称为仿射遍历)。

在哈斯克尔

在 Haskell 中流行的原因是光学的表现非常简洁。所有光学器件都只是某种形式的函数,可以使用函数组合来组合在一起。这样可以实现非常轻量的嵌入,从而可以轻松地将光学器件集成到你的程序中。此外,由于编码的细节,功能组合还自动计算我们组成的两个光学系统的上限。这意味着我们可以在不进行显式转换的情况下将相同的组合器重复用于不同的光