什么是棱镜?

2024-02-21

我试图更深入地了解lens库,所以我尝试使用它提供的类型。我已经有了一些使用镜头的经验,知道它们的强大和方便。所以我转向了 Prisms,但我有点迷失了。棱镜似乎可以做两件事:

  1. 确定实体是否属于总和类型的特定分支,如果属于,则捕获元组或单例中的基础数据。
  2. 解构和重建一个实体,可能会在过程中修改它。

第一点似乎很有用,但通常不需要实体的所有数据,并且^?使用平光镜片可以得到Nothing如果相关字段不属于实体所代表的分支,就像棱镜一样。

第二点……我不知道,可能有用途吗?

所以问题是:我能用棱镜做哪些其他光学器件做不到的事情?

Edit:感谢大家的精彩回答和进一步阅读的链接!我希望我能全部接受。


镜头的特点是has-a关系;棱镜的特点是is-a关系。

A Lens s a says "s has an a"; 它有方法可以精确地得到一个a从一个s并恰好覆盖一个a in an s. A Prism s a says "a is an s"; 它有方法向上转型a to an s并(试图)贬低s to an a.

将这种直觉放入代码中,可以为您提供熟悉的“get-set”(或“costate comonad coalgebra”)镜头公式,

data Lens s a = Lens {
    get :: s -> a,
    set :: a -> s -> s
}

以及棱镜的“向上-向下”表示,

data Prism s a = Prism {
    up :: a -> s,
    down :: s -> Maybe a
}

up注入一个a into s(不添加任何信息),以及down测试是否s is an a.

In lens, up拼写为review https://hackage.haskell.org/package/lens-4.16.1/docs/Control-Lens-Review.html#v:review and down is preview https://hackage.haskell.org/package/lens-4.16.1/docs/Control-Lens-Fold.html#v:preview。没有Prism构造函数;你用the prism'智能构造函数 https://hackage.haskell.org/package/lens-4.16.1/docs/Control-Lens-Prism.html#v:prism-39-.


你能用a做什么Prism?注入和项目总和类型!

_Left :: Prism (Either a b) a
_Left = Prism {
    up = Left,
    down = either Just (const Nothing)
}
_Right :: Prism (Either a b) b
_Right = Prism {
    up = Right,
    down = either (const Nothing) Just
}

镜头不支持这一点 - 你不能写Lens (Either a b) a因为你无法实施get :: Either a b -> a。作为一个实际问题,你can写一个Traversal (Either a b) a,但这不允许您创建Either a b从一个a- 它只会让你覆盖a它已经在那里了。

Aside:我认为这个微妙的点是关于Traversals 是您对部分记录字段感到困惑的根源。

^?使用平光镜片可以得到Nothing如果相关字段不属于实体代表的分支

Using ^?与真实的Lens永远不会回来Nothing,因为一个Lens s a准确识别一个a里面一个s。 当面对部分记录字段时,

data Wibble = Wobble { _wobble :: Int } | Wubble { _wubble :: Bool }

makeLenses将生成一个Traversal, not a Lens.

wobble :: Traversal' Wibble Int
wubble :: Traversal' Wibble Bool

举个例子来说明如何Prism可以应用到实践中,看看Control.Exception.Lens http://hackage.haskell.org/package/lens-4.16.1/docs/Control-Exception-Lens.html,它提供了一个集合Prisms 进入 Haskell 的可扩展Exception等级制度。这使您可以执行运行时类型测试SomeExceptions 并将特定异常注入SomeException.

_ArithException :: Prism' SomeException ArithException
_AsyncException :: Prism' SomeException AsyncException
-- etc.

(这些是实际类型的稍微简化的版本。实际上,这些棱镜是重载的类方法。)

从更高的层次思考,某些整个程序可以被认为是“基本上是一个Prism”。编码和解码数据就是一个例子:您始终可以将结构化数据转换为String,但不是每个String可以解析回来:

showRead :: (Show a, Read a) => Prism String a
showRead = Prism {
    up = show,
    down = listToMaybe . fmap fst . reads
}

总而言之,Lenses and Prism它们一起编码了面向对象编程的两个核心设计工具:组合和子类型。Lenses 是 Java 的一流版本. and =运营商,以及Prisms 是 Java 的一流版本instanceof和隐式向上转换。


一种富有成效的思考方式Lenses 是它们为您提供了一种拆分复合材料的方法s成为一个聚焦的价值a和一些背景c。伪代码:

type Lens s a = exists c. s <-> (a, c)

在这个框架中,一个Prism为您提供一种查看s作为一个a或一些上下文c.

type Prism s a = exists c. s <-> Either a c

(我将让你自己相信这些与我上面演示的简单表示是同构的。尝试实现get/set/up/down对于这些类型!)

从这个意义上说Prism is a co-Lens. Either是以下的绝对对偶(,); Prism是以下的绝对对偶Lens.

您还可以在以下内容中观察到这种二元性:“泛函光学” http://www.cs.ox.ac.uk/people/jeremy.gibbons/publications/poptics.pdf公式 -Strong http://hackage.haskell.org/package/profunctors-5.2.2/docs/Data-Profunctor.html#t:Strong and Choice http://hackage.haskell.org/package/profunctors-5.2.2/docs/Data-Profunctor.html#t:Choice是双重的。

type Lens  s t a b = forall p. Strong p => p a b -> p s t
type Prism s t a b = forall p. Choice p => p a b -> p s t

This is 或多或少的表示lens使用,因为这些Lenses and Prisms 非常可组合。你可以作曲Prism变得更大Prisms ("a is an s, which is a p“) 使用(.);组成一个Prism with a Lens给你一个Traversal.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

什么是棱镜? 的相关文章

  • 在 Haskell 中将字节转换为 Int64s/Floats/Doubles

    我正在尝试解析 Haskell 中的二进制文件格式 Apple 的二进制属性列表格式 该格式所需的内容之一是将字节序列视为 a 无符号 1 2 或 4 字节整数 b 有符号 8 字节整数 c 32 位floats d 64 位doubles
  • 如何使用 Haskell 中的 thyme 库从 Int 值创建 UTCTime?

    我有年 月 日 小时和分钟值 所有这些都是类型Int 我怎样才能将它们转换为UTCTime or UniversalTime 需要导入以下内容 import Control Lens import Data Thyme Clock impo
  • 通过 Emacs 评估 ghci 或 Hugs 中的缓冲区

    在 Emacs 中使用 sml mode 我已经能够使用以下命令将缓冲区内容直接发送到较差的 SML 进程C c C b 现在我只想用 Haskell 做同样的事情 Haskell 模式似乎不支持这一点 所以我想知道 使用 Emacs 和
  • 访问函数中的环境

    In main我可以读取我的配置文件 并将其提供为runReader somefunc myEnv正好 但somefunc不需要访问myEnv读者提供 链中的下一对也没有提供 需要 myEnv 中某些内容的函数是一个微小的叶函数 如何在不将
  • ErrorT 已弃用,但 exceptT 不适合

    我有一个一元计算 在某些时候 由于单子模式匹配 它开始需要 MonadFail 约束 我的简单解决方法是使用以下命令运行它 fmap either error id runErrorT 然而哎呀 Deprecated Use Control
  • Haskell 中的实例声明

    我有这两个功能 primes sieve 2 where sieve p xs p sieve x x lt xs x mod p gt 0 isPrime number number 1 null x x lt takeWhile x g
  • 将数据类型设置为 Kind * -> * 这不是函子

    布伦特 约尔吉类型分类百科全书 https www haskell org haskellwiki Typeclassopedia给出以下练习 举一个类型的例子 gt 不能将其制成 的实例Functor 不使用undefined 请告诉我什
  • 我应该在 Turtle 或 Foldl 包中使用折叠吗?

    我在使用 Turtle 时遇到了一些困难 直到盯着难以理解的错误消息几分钟后才意识到我使用了错误的fold功能 https hackage haskell org package turtle 1 5 8 docs Turtle Shell
  • 如何在 Haskell 中向右或向左移动列表的 1 个元素?

    嗨 我一直在寻找答案 但找不到 假设我们有一个像这样的列表 1 10 4 5 3 我怎样才能将 5 向左移动 使这个列表变成 1 10 5 4 3 我尝试过了swapElementsAt通过找到该元素的索引 但它看起来非常不足 swapEl
  • 搜索重写规则

    有什么办法可以浏览或搜索重写规则吗 当我使用像这样的标志时 ddump rule firings or ddump rule rewrites我只是得到了触发的规则的名称以及它引起的重写 但没有得到实际的规则本身 理想情况下 我想通过 GH
  • 如何在 Haskell 中安装库?

    我尝试使用控制 Monad Extra andM https hackage haskell org package extra 1 7 10 docs Control Monad Extra html import Control Mon
  • 标准的能力

    我发现了一些使用标准的旧例子here http www serpentine com blog 2009 09 29 criterion a new benchmarking library for haskell 看起来好像早在 2009
  • Haskell / GHC - 是否有“警告不完整模式”的中缀标签/编译指示

    我正在寻找一个可以对特定的不完整模式发出警告的编译指示 它会使编译器失败并显示以下 假设的 代码 FAILIF incomplete patterns f Int gt Int f 0 0 我正在尝试使用 Arrows 编写一个 编译器 并
  • Haskell Stack 从 github 安装包依赖项

    是否可以使用 Haskell 堆栈从 github 安装软件包的版本 例如在一个 cabal or a stack yaml文件 如何在 git repo branch revision 上指向依赖项 对于堆栈 The 的文档stack y
  • 找不到模块“Yesod”

    我有以下代码 LANGUAGE TypeFamilies QuasiQuotes MultiParamTypeClasses TemplateHaskell OverloadedStrings module Simple where imp
  • Haskell:IORef 的性能

    我一直在尝试在 Haskell 中编码一个需要使用大量可变引用的算法 但与纯粹的惰性代码相比 它 也许并不奇怪 非常慢 考虑一个非常简单的例子 module Main where import Data IORef import Contr
  • 这个对自身单位的列表理解是如何工作的?

    在 haskell IRC 频道中有人问 是否有一种简洁的方法来定义一个列表 其中第 n 个条目是之前所有条目的平方和 我认为这听起来像一个有趣的谜题 递归定义无限列表是我真正需要练习的事情之一 所以我启动了 GHCi 并开始尝试递归定义
  • Haskell 对于 Web 应用程序来说足够成熟吗? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 在 monad 转换器类型类中使用列表 monad?

    我的目标是创建一个在 ReaderT WriterT 堆栈或 RWS 堆栈中使用列表 monad 的函数 更一般地说 如何在 mtl 类型类 例如 MonadReader MonadWriter 中使用列表 monad 我为什么要尝试这样做
  • 检查对以下内容的理解:“变量”与“变量” “价值”、“功能”与“抽象”

    这个问题是后续问题this one https stackoverflow com questions 25327705 is function a sort of variable 25329157 25329157在学习 Haskell

随机推荐

  • 在我获取输入数据之前,什么会对其进行重新格式化?

    我有一个数据湖存储帐户 我有一个充满包含 JSON 格式数据的文件的目录 其中包括一些包含 ISO 8601 格式时间的字符串值 即 reading time 2008 09 15T15 53 00 91077 现在 当我使用数据工厂创建管
  • Android中保存同一个Activity的多个实例状态

    我正在开发一个 Android 应用程序 当数据来自使用相同额外内容的相同 Activity 时 我希望避免重新加载类似数据 具体来说 当我使用 extra 启动 Activity A 时 我使用这个 extra 从服务器加载远程数据 通过
  • Android Studio:“Gradle 同步失败:无法从选定的 JDK 运行 JVM。”

    自从安装Android Studio 3 2后 我一直无法运行Java 我尝试过jdk 8u181 windows x64 jdk 10 0 2 windows x64 bin jdk 11 windows x64 bin 环境PATH并重
  • 映射到同类 Traversable 的 Traversable 类型

    简洁版本 Scala 中的大多数泛型集合都有一个map实际上 该方法将返回相同类型的集合 List A map f A gt B 返回一个List B 例如 Scala 集合库就是为了实现这一目标而明确设计的 如果我想编写对任何此类集合具有
  • 使用 Selenium 上传文件失败

    我正在尝试使用 Selenium 在 Eclipse 上使用以下代码将文件上传到表单 search driver find element by xpath input type file search send keys D test t
  • 使用 image.complete 查找图像是否缓存在 chrome 上?

    我一直试图找出外部图像是否用js缓存在浏览器上 这是我到目前为止的代码
  • XML 转换导致 FileNotFoundException

    由于缺乏信息 我之前发布的问题已关闭 如果我在这里遗漏了什么 请告诉我 转换器似乎将 file 添加到我的文件路径的开头 我在 Solaris 环境中工作 应用转换时会发生以下情况 DOMSource sourcexml new DOMSo
  • Android模拟器无法创建上下文0x3005

    我对 Android 开发完全陌生 我正在尝试在 Android 中执行一个小任务 注册表单 但是 我收到以下错误 2013 12 05 11 06 26 Emulator could not get wglGetExtensionsStr
  • C++ 随机猜数字游戏

    我必须编写一个程序来运行随机猜谜游戏 游戏的数字是从 1 到 100 猜测者可以尝试 20 次 最后应该被问是否愿意再玩一次 如果猜测者高或低 还必须有多种打印输出选项 我已经完成了程序的一部分 我知道我仍然需要添加其他打印输出选项 但现在
  • 解释UnixTime毫秒

    我正在尝试找到更好的方法在 C 中将 DateTime 转换为 unix 时间戳 我发现有一个 DateTimeOffset ToUnixTimeMilliseconds 方法 public long ToUnixTimeMilliseco
  • MvxCachingFragmentCompatActivity消失了吗?

    我正在尝试升级到 MvvmCross 5 2 但在 MvxCachingFragmentCompatActivity 上出现语法错误 这个班级消失了吗 正如 5 2 博客中所解释的 https www mvvmcross com mvvmc
  • 如何更新d3表?

    鼠标移动时更新 d3 js 表时遇到一些问题 这是一个简化的example https jsfiddle net lszhou2115 npzjLng9 6 在jsfiddle中 这是主要代码 function mousemove var
  • 如何修复 ubuntu 中的“没有名为‘kivy._clock’的模块”错误?

    我正在尝试使用 Ubuntu 16 04 for Python 3 6 安装 kivy GUI lib 我尝试执行kivy官方网站中的步骤 https kivy org doc stable installation installatio
  • GAE java中通过证书进行客户端身份验证

    我正在写一份申请GAE java通过其身份验证用户证书 我已经使用创建了一个自签名证书keytool在客户端 我还在 Google 应用程序引擎中为我的应用程序启用 https 请求 申请流程非常简单 用户使用任何浏览器进入应用程序的主页
  • 为什么 c++ std::max_element 这么慢?

    我需要找到向量中的最大元素 所以我使用std max element 但我发现它是一个非常慢的函数 所以我编写了自己的版本并设法获得 x3 更好的性能 下面是代码 include
  • 如果等于运算符没有被空格包围,为什么它不起作用?

    我尝试了以下脚本 bin bash var1 Test 1 var2 Test 2 if var1 var2 then echo Equal else echo Not equal fi 它给了我Equal 虽然应该已经打印出来了Not e
  • 如何在 ASP.NET Core 2.0 和 EF Core 2.0 中将应用程序设置从项目根获取到 IDesignTimeDbContextFactory 实现

    我正在 ASP NET Core 2 0 中构建应用程序 但在 EntityFramework 迁移方面遇到问题 我的 DbContext 位于一个单独的项目中 解决方案名称 项目名称前缀 Data 因此我创建了 IDesignTimeDb
  • D3 动态重绘Y轴

    我想创建一个具有多个 线性 轴的动态图 绘制轴后 我想 当新数据到达时 更改数据域并重新绘制 更新轴 我可以使用 D3 选择现有轴并执行此操作 还是必须在代码中显式保存每个轴 我希望我的问题不会令人困惑 init all Y Axis ea
  • C++ STL 容器和就地构建

    请考虑以下事项 class CMyClass public CMyClass printf Constructor n CMyClass const CMyClass printf Copy constructor n int main s
  • 什么是棱镜?

    我试图更深入地了解lens库 所以我尝试使用它提供的类型 我已经有了一些使用镜头的经验 知道它们的强大和方便 所以我转向了 Prisms 但我有点迷失了 棱镜似乎可以做两件事 确定实体是否属于总和类型的特定分支 如果属于 则捕获元组或单例中