箭头定律:首先仅取决于该对的第一个分量。为什么我们需要这个?

2023-12-19

约翰·休斯 (John Hughes) 在他的“将单子概括为箭头”中写道(第 8 章):

我们将财产形式化first f仅取决于对的第一个分量,如下所示:first f >>> arr fst = arr fst >>> f

据我了解,法律会过滤掉此类实施:

newtype KleisliMaybe a b = KMb { runKMb :: a -> Maybe b }

instance Category KleisliMaybe where 
 ...

instance Arrow KleisliMaybe where
 first f = KMb $ const Nothing
 ...

但对于这种情况,措辞似乎有点奇怪(我会选择“first没有副作用”或类似的情况)。

那么,还有哪些其他原因需要保留它呢?

此外,还有一条定律:first f >>> second (arr g) = second (arr g) >>> first f。我没有找到它过滤掉的任何实现(我做到了 - 查看编辑)。这部法律对我们有什么帮助?


编辑:对后一条法律的更多思考。

看看下面的代码片段:

newtype KleisliWriter = KW { runKW :: a -> (String, b) }

instance Category KleisliWriter where
 ...

instance Arrow KleisliWriter where
 arr f = KW $ \ x -> ("", f x)
 first  (KW f) = KW $ \ ~(a, d) -> f a >>= (\ x -> ("A", (x, d)))
 second (KW f) = KW $ \ ~(d, b) -> f b >>= (\ x -> ("B", (d, x)))

这样的实例的行为方式如下:

GHCi> c = KW $ \ x -> ("C", x)
GHCi> fst . runKW (first c >>> second (arr id)) $ (1, 2)
"CAB"
GHCi> fst . runKW (second (arr id) >>> first c) $ (1, 2)
"BCA"

据我所知,我们没有法律规定second f = swap >>> first f >>> swap。因此,我们可以禁止两者second and first该法律有任何副作用。然而,最初的措辞似乎仍然没有再次暗示这一点:

...我们形式化了直觉,即该对的第二个组成部分不受first f作为法律...

这些法律只是纯粹的形式化确凿证据吗?


简短回答:有一对不同的法律涵盖“first and second无副作用”:

first (arr f) = arr (first f)
second (arr f) = arr (second f)

想了想之后,我THINK您已经确定的两条法律:

first f >>> arr fst          =   arr fst >>> f                -- LAW-A
first f >>> second (arr g)   =   second (arr g) >>> first f   -- LAW-B

事实上,它们是多余的,因为它们遵循那些无副作用定律、其他定律和一些“自由定理”。

你的反例违反了无副作用法则,所以这就是为什么它们也违反了 LAW-A 和/或 LAW-B。如果有人有一个真正的反例,遵守无副作用定律,但违反了 LAW-A 或 LAW-B,我会很有兴趣看到它。

长答案:

该物业“first没有副作用(至少其本身没有副作用)”,该文第 8 条前面所述的法律更好地形式化了这一点:

first (arr f) = arr (first f)

回想一下,休斯说,如果箭头可以写,那么它就是“纯粹的”(相当于“没有副作用”)arr expr。因此,该定律指出,给定任何已经是纯粹的计算,因此可以写成arr f, 申请first该计算也会导致纯计算(因为它的形式是arr expr with expr = first f)。所以,first不引入杂质/本身不产生影响。

另外两条定律:

first f >>> arr fst          =   arr fst >>> f                -- LAW-A
first f >>> second (arr g)   =   second (arr g) >>> first f   -- LAW-B

旨在捕捉这样的想法:对于特定的instance Arrow Foo和一个特定的箭头动作f :: Foo B C, 那个行动:

first f :: forall d. Foo (B,d) (C,d)

作用于其输入/输出对的第一个组件,就好像第二个组件不存在一样。定律对应于以下性质:

  1. LAW-A:输出组件C并且任何副作用仅取决于输入B, 不输入d(即,不依赖于d)
  2. LAW-B:组件d不变地通过,不受输入影响B或任何副作用(即,对d)

对于 LAW-A,如果我们考虑行动first f :: Foo (B,d) (C,d)并重点关注C使用纯函数提取其输出的组成部分:

first f >>> arr fst :: Foo (B,d) C

那么结果与我们首先使用纯操作强制删除第二个组件相同:

arr fst :: Foo (B,d) B

并允许原来的动作f只采取行动B:

arr fst >>> f :: Foo (B,d) C

这里,结构first f >>> arr fst行动留下了这样的可能性:first f可以取决于d输入的组成部分在制定其副作用和构建C其输出的组成部分;但是,该结构的arr fst >>> f行动通过消除这种可能性d在允许任何不平凡的计算之前通过纯动作来组件f。这两个行为是平等的(法律)这一事实清楚地表明:first f产生一个C输出(和副作用,通过f, since first本身没有额外的效果)B以这样的方式输入can't还取决于d input.

LAW-B 更难。形式化该属性的最明显的方法是伪定律:

first f >>> arr snd = arr snd

这直接说明了first f不会改变提取的(arr snd) 第二个组成部分。然而,休斯指出,这是too限制性的,因为它不允许first f产生副作用(或至少任何可以在纯粹的行动中幸存下来的副作用)arr snd)。相反,他提供了更复杂的法律:

first f >>> second (arr g)   =   second (arr g) >>> first f

这里的想法是,如果first f曾经修改过d值,那么就会有some以下两个操作不同的情况:

-- `first f` changes `inval` to something else
second (arr (const inval)) >>> first f
-- if we change it back, we change the action
second (arr (const inval)) >>> first f >>> second (arr (const inval))

但是,由于 LAW-B,我们有:

second (arr (const inval)) >>> first f >>> second (arr (const inval))
-- associativity
= second (arr (const inval)) >>> (first f >>> second (arr (const inval)))
-- LAW-B
= second (arr (const inval)) >>> (second (arr (const inval)) >>> first f)
-- associativity
= (second (arr (const inval)) >>> (second (arr (const inval))) >>> first f
-- second and arr preserve composition
= second (arr (const inval >>> const inval)) >>> first f
-- properties of const function
= second (arr (const inval)) >>> first f

所以动作是相同的,与我们的假设相反。

然而,我猜想 LAW-A 和 LAW-B 都是多余的,因为我相信(见下面我的犹豫)它们遵循其他定律加上签名的“自由定理”:

first f :: forall d. Foo (B,d) (C,d)

假设first and second满足无副作用定律:

first (arr f) = arr (first f)
second (arr f) = arr (second f)

那么 LAW-B 可以重写为:

first f >>> second (arr g)              = second (arr g) >>> first f
-- no side effects for "second"
first f >>> arr (second g)              = arr (second g) >>> first f
-- definition of "second" for functions
= first f >>> arr (\(x,y) -> (x, g y))  = arr (\(x,y) -> (x, g y)) >>> first f

最后一个陈述只是自由定理first f。 (直觉上,因为first f是多态的类型d,任何纯粹的行动d必然是“看不见的”first f, so first f并且任何此类行为都会交换。)类似地,有一个自由定理:

first f >>> arr fst :: forall d. Foo (B,d) C

这抓住了这样一个想法,因为这个签名是多态的d,没有纯粹的预作用d可以影响动作:

arr (\(x,y) -> (x, g y)) >>> (first f >>> arr fst) = first f >>> arr fst

但左边可以重写:

-- by associativity
(arr (\(x,y) -> (x, g y)) >>> first f) >>> arr fst
-- by rewritten version of LAW-B
(first f >>> arr (\(x,y) -> (x, g y))) >>> arr fst
-- by associativity
first f >>> (arr (\(x,y) -> (x, g y)) >>> arr fst)
-- `arr` preserves composition
first f >>> arr ((\(x,y) -> (x, g y)) >>> fst)
-- properties of fst
first f >>> arr fst

给出右侧。

我只是在这里犹豫,因为我不习惯思考可能有效的箭头而不是函数的“自由定理”,所以我不能 100% 确定它会通过。

我很想知道是否有人能为这些违反 LAW-A 或 LAW-B 但满足无副作用定律的法律提出真正的反例。你的反例违反 LAW-A 和 LAW-B 的原因是它们违反了无副作用法则。对于你的第一个例子:

> runKMb (first (arr (2*))) (2,3)
Nothing
> runKMb (arr (first (2*))) (2,3)
Just (4,3)

对于你的第二个:

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

箭头定律:首先仅取决于该对的第一个分量。为什么我们需要这个? 的相关文章

  • Haskell,范围缩小到无步骤[重复]

    这个问题在这里已经有答案了 为什么在 Haskell 中工作范围不能降低到没有步骤 7 1 gt 但只工作这个 7 6 1 gt 7 6 5 4 3 2 1 Haskell 无法知道您想要执行 1 除非您给出提示 在某些情况下 您可能需要一
  • Haskell 真的是纯粹的吗(有任何语言可以处理系统外的输入和输出)吗?

    在谈到函数式编程中的 Monad 后 该功能是否真的使语言变得纯粹 或者它只是黑板数学之外的现实世界中计算机系统推理的另一张 免狱卡 EDIT 这不是有人在这篇文章中所说的火焰诱饵 而是一个真正的问题 我希望有人能用它来击倒我并说 证明 它
  • 不同 hs 文件中的函数分离时堆栈空间溢出

    我有一个巨大的 haskell 文件 它编译和运行没有任何问题 我想将一些函数和类型定义放在通用 hs 文件中的单独模块中 然后将其导入我的主模块中 虽然主程序编译时没有任何错误 它还编译导入的模块 但当我尝试运行它时 出现堆栈空间溢出 I
  • 可以通过Data.Function.fix来表达变形吗?

    我有这个可爱的fixana这里的函数执行速度比她的姐妹快 5 倍左右ana 我有一个criterion报告支持我这一点 ana alg Fix fmap ana alg alg fixana alg fix f gt Fix fmap f
  • Haskell 二进制解析

    我一直在尝试在 haskell 中实现一个协议解析器 而且我对这门语言还很陌生 特别是当涉及到 monad 时 我一直在使用binary 0 5 0 2 并描述了协议的标头和所有有效负载 我想要解析的消息如下所示 header payloa
  • 如何、为什么以及何时使用“.Internal”模块模式?

    我在上面看到了几个包裹hackage http hackage haskell org packages archive pkg list html其中包含模块名称 Internal作为他们的姓氏组成部分 例如Data ByteString
  • 'lens' 的阴谋集团依赖性解析失败

    我刚刚做了一个阴谋更新并尝试从 hackage 安装 lens 这给了我以下错误 cabal install j lens Resolving dependencies Configuring dlist 0 7 0 1
  • “反向”使用 Maybe Monad

    假设我有很多功能 f a gt Maybe a g a gt Maybe a h a gt Maybe a 我想按以下方式组合它们 如果 f 返回 Nothing 则计算 g 如果 g 返回 Nothing 则计算 h 如果其中任何一个计算
  • 是否有一个基于对象身份的、线程安全的记忆库?

    我知道记忆化似乎是堆栈溢出的 haskell 标签上的一个长期话题 但我think以前没有人问过这个问题 我知道 Haskell 有几个不同的 现成 记忆库 memo combinators 和 memotrie 包 利用涉及惰性无限数据结
  • 将 Either 列表转换为其中包含列表的 Either 列表

    我是 Haskell 的初学者 我正在编写一些使用 Haskell 的代码Either https hackage haskell org package base 4 9 0 0 docs Data Either html用于错误处理 E
  • 反应性香蕉时间延迟

    我已经查阅了文档反应香蕉 http hackage haskell org package reactive banana 而且我找不到指定明确时间延迟的方法 举例来说 我想采取Event t a并将其所有发生的事件移至未来 1 秒 或获取
  • Haskell 错误处理方法

    毫无疑问 Haskell 中有多种机制来处理错误并正确处理它们 错误单子 要么 也许 异常等 那么为什么用其他语言编写容易出现异常的代码比用 Haskell 感觉更简单呢 假设我想编写一个命令行工具来处理命令行上传递的文件 我想 验证提供的
  • 解析 PHOAS 表达式

    我想我理解 PHOAS 参数化高阶抽象语法 我明白了如何漂亮地打印一个表达式 参见http www reddit com r haskell comments 1mo59h phoas for free by edward kmett cc
  • 如何处理在组合下发生变化的类型?

    我最近读了一篇非常有趣的论文单调性类型 https infoscience epfl ch record 231867 files monotonicity types pdf其中描述了一种新的 HM 语言 该语言可以跟踪操作之间的单调性
  • 为什么解析器组合器“seq”用“bind”和“return”定义?

    我正在读这个article http eprints nottingham ac uk 237 1 monparsing pdf关于解析器组合器并且不理解以下内容 他们说使用seq 见下文 导致解析器将嵌套元组作为结果 操作起来很混乱 se
  • Parsec 函数“parse”和类“Stream”的类型签名

    约束条件是什么 Stream s Identity t 下面的类型声明是什么意思 parse Stream s Identity t gt Parsec s a gt SourceName gt s gt Either ParseError
  • Haskell 类型定义,=> 等

    我正在使用 Learn You a Haskell 来学习 Haskell 第 54 页上有一个 像这样执行 take Num i Ord i gt i gt a gt a take n n lt 0 take take n x xs x
  • Haskell cabal:我刚刚安装了软件包,但现在找不到软件包

    在这里 http haskell org haskellwiki Cabal Install I just installed packages 2C but now the packages are not found这是我可以找到我正在
  • 在 Haskell 中创建 100 万个线程需要多长时间?

    据我了解 Haskell 有绿色线程 但它们的重量有多轻 是否可以创建100万个线程 或者 100 000 个线程需要多长时间 from here http www reddit com r programming comments a4n
  • Haskell 中的所有图形和 Web 库是如何实现的?

    我才开始学习Haskell 我读到它是一种纯函数式语言 其中的所有内容都是不可变的 因此 输入输出 写入和读取数据库之类的事情会导致状态的可变性 我知道 Haskell 中有一种叫做 monad 的东西 它允许在 Haskell 中使用命令

随机推荐

  • iPhone 应用程序启动关闭的分配时间

    iPhone 应用程序 以及可能的其他重要例程 的启动和关闭需要花费多少时间 我的 iPhone 上的程序曾被过于热心的操作系统杀死吗 如果应用程序在 20 秒内没有响应 iPhone 上的看门狗计时器将终止您的应用程序 请注意 Xcode
  • 如何制作 iPython/Jupyter 中内联的 NLTK draw() 树

    对于 iPython Jupyter 中的 Matplotlib 绘图 您可以使笔记本绘图内联 matplotlib inline 如何对树的 NLTK draw 做同样的事情 这是文档http www nltk org api nltk
  • C# 中的多线程目录循环

    我试图循环遍历所有文件和文件夹 并对具有特定扩展名的所有文件执行操作 这种方法工作得很好 但我想使它成为多线程 因为当完成数万个文件时 它真的很慢 我会使用多线程进行成像会加快速度 我只是不确定在这种情况下如何使用线程 doStuff从文件
  • 加载时间:使用 PHP 的 DOMDocument 还是使用正则表达式解析 HTML 更快?

    我正在将图像从我的 Flickr 帐户提取到我的网站 并且我使用了大约九行代码来创建一个用于提取图像的 preg match all 函数 我已经读过好几次了 通过 DOM 解析 HTML 会更好 就我个人而言 我发现通过 DOM 解析 H
  • 向右移动菜单最后一项

    德尔福Xe2U4 主菜单项 文件 选项 帮助 名称 HelpMenuItem 2 个按钮 使用 StyleManager Xe2 在项目选项中启用 xe2 主题 并默认设置 Metro Blue Procedure TForm1 Right
  • 启用 Wi-Fi 时不接收移动状态状态更改事件

    当移动数据启用 禁用时我需要收到通知 为此 我使用 BroadcastReceiver 并注册到 ConnectivityManager CONNECTIVITY ACTION 事件 然而 只有当 Wi Fi 被禁用时才会触发该事件 一旦我
  • 按特定日期名称找出下周时间表的最佳方法

    想象我有一个名为NextSend代表DateTime Value 4 11 2011 10 30 00 AM Monday 假设我有一个必须每周在特定日期发送的时间表 Monday 在这种情况下 为了弄清楚下周的时间表 我最终得到了解决方案
  • 无法使用 Jena 写入大型 owl 文件

    我正在尝试将数据库表中包含的数据转换为一组三元组 因此我正在使用 Jena java 库编写一个 owl 文件 我已经成功地使用少量表记录 100 完成了此操作 这些记录对应于 owl 文件中的近 20 000 行 我对此感到满意 为了编写
  • IIS Windows 身份验证 401 未经授权

    我有一个想要使用 Windows 身份验证的子应用程序 我希望当用户第一次到达该页面时 即使在域中也会弹出登录框 当我关闭内核模式身份验证时 会弹出登录框 但在 3 次登录尝试后失败 并显示错误 401 未授权 如果我打开此功能 它甚至不会
  • ZF2 - 如果路由器匹配多个路由,将调度什么?

    那么 如果我有一个可能与许多路由匹配的 url 该怎么办 哪条路由会获胜 将调度哪个操作 是不是很简单 先定义 先调度 以下是路线示例 route catchall gt array type gt regex options gt arr
  • 作为 PySpark 的 reduceByKey 的键的列表

    我试图对格式的数据调用 pyspark 的 reduceByKey 函数 a b c 1 a b c 1 a d b e 1 看来 pyspark 不会接受数组作为普通键中的键 通过简单地应用 reduceByKey add 来减少值 我已
  • 如何在Java2D中旋转矩形

    我想在方法中旋转一个矩形 但不明白如何做到这一点并尝试如下 private void setBoundaryRotate Rectangle b int radio AffineTransform transform new AffineT
  • Chrome 不允许 HTTP 托管网站访问摄像头和麦克风

    我在用着反应网络摄像头 https github com mozmorris react webcam为应用程序拍摄自拍照 在本地主机上 react webcam 工作得很好 而在 HTTP 托管的网络服务器上 Chrome 上默认拒绝摄像
  • Python:我应该如何使实例变量可用?

    假设我有 class myclass def init self self foo bar 其中 foo 的值需要可供 myclass 的用户使用 直接从 myclass 的实例读取 foo 的值可以吗 我应该向 myclass 添加 ge
  • 打开 RDB 文件失败...只读文件系统

    我正在尝试在我的 redis 实例上执行保存或 bgsave 以运行备份 恢复过程 但是 当我尝试保存时出现错误 532 M 28 Jun 23 58 30 396 Failed opening the RDB file backup rd
  • 使用应用服务和 Azure SQL 的用户分配身份是否有效?

    我正在尝试让应用服务与 Azure Sql 数据库连接 我可以使用相同的代码很好地使用 git 处理系统分配的身份 但我更喜欢使用用户分配的身份 UAI 但我无法让它工作 我所做的步骤 通过门户创建了一个 UAI UAI 的名称为 uai
  • 重新映射 vim :x 来关闭缓冲区,仅当它是最后一个缓冲区时才退出

    I would like to change the x command in Vim so that it closes a buffer unless it is the last buffer then it should behav
  • 清单引用文件“Bing.Maps.dll”,该文件不是有效负载的一部分

    错误 1 清单引用文件 Bing Maps dll 该文件不是有效负载的一部分 C Users xxx Desktop xxx Applicationxx Applicationxx Package appxmanifest Applica
  • 什么是好的 Databricks 工作流程

    我使用 Azure Databricks 以及笔记本和管道进行数据处理 我对当前的工作流程不满意 在不中断生产的情况下 无法对生产中使用的笔记本进行修改 当我想要开发更新时 我会复制笔记本 更改源代码直到我满意为止 然后用新笔记本替换生产笔
  • 箭头定律:首先仅取决于该对的第一个分量。为什么我们需要这个?

    约翰 休斯 John Hughes 在他的 将单子概括为箭头 中写道 第 8 章 我们将财产形式化first f仅取决于对的第一个分量 如下所示 first f gt gt gt arr fst arr fst gt gt gt f 据我了