双递归定义列表的双无限列表

2024-01-10

Context

我问的是修补递归定义的列表 https://stackoverflow.com/q/53988970/12274另一天。我现在尝试通过在 2D 列表(列表的列表)上操作来将其提升一个级别。

我将使用帕斯卡三角形作为示例,例如这个美丽的 https://stackoverflow.com/a/27233941/12274:

pascals = repeat 1 : map (scanl1 (+)) pascals
[1,1,1,1,1,1...
[1,2,3,4,5...
[1,3,6,10...
[1,4,10...
[1,5...
[1...

Question

我想这样表达:

  1. 我将提供自己的第一行和第一列(上面的示例假设第一行是repeat 1,这是足够可修复的,第一列是repeat (head (head pascals)),这会更加棘手)

  2. 每个元素仍然是上面的元素和它左边的元素的函数。

  3. 总的来说,它本身就是一个函数,足以使其能够在定义中插入修补函数并让它传播修补程序。

所以从外面看,我想找一个f函数这样我就可以定义pascal像这样:

pascal p = p (f pascal)

...以便pascal id与示例中的相同,并且pascal (patch (1,3) to 16)产生类似:

[1,1,1,1, 1,1...
[1,2,3,16,17...
[1,3,6,22...
[1,4,10...
[1,5...
[1...

我在哪里

让我们首先定义并提取第一行和第一列,这样我们就可以使用它们并且不会滥用它们的内容。

element0 = 1
row0 = element0 : repeat 1
col0 = element0 : repeat 1

更新要使用的定义row0很容易:

pascals = row0 : map (scanl1 (+)) pascals

但第一栏仍然是element0。更新以获取它们col0:

pascals = row0 : zipWith newRow (tail col0) pascals
  where
    newRow leftMost prevRow = scanl (+) leftMost (tail prevRow)

现在我们已经满足了第一个要求(自定义第一行和第一列)。在没有打补丁的情况下,第二个仍然很好。

我们甚至得到了第三个元素的一部分:如果我们修补一个元素,它就会向下传播,因为newRow定义为prevRow。但它不会向右传播,因为(+)运行于scanl的内部累加器,并从leftMost,在这种情况下这是一个明确的。

我尝试过的

从这里开始,正确的做法似乎是真正分离关注点。我们想要我们的初始化器row0 and col0定义中尽可能明确,并找到一种独立定义矩阵其余部分的方法。存根:

pascals = row0 : zipWith (:) (tail col0) remainder
[1,1,1,1,1,1,1,1,1,1...
[1,/-------------------
[1,|
[1,|
[1,|
[1,|  remainder
[1,|
[1,|
[1,|
[1,|

然后我们希望余数直接根据整体定义。自然的定义是:

remainder = zipWith genRow pascals (tail pascals)
  where genRow prev cur = zipWith (+) (tail prev) cur
[1,1,1,1,1,1,1,1,1,1...
<<loop>>

第一行结果很好。为什么要循环?遵循评估有助于:pascals被定义为缺点,其汽车很好(并打印)。 cdr是什么?它是zipWith (:) (tail col0) remainder。这个表达式是一个[] or (:)?这是最短的参数tail col0 and remainder. col0是无限的,它就像空一样remainder, i.e. zipWith genRow pascals (tail pascals)。就是它[] or (:)?出色地,pascals已经被评估为(:), but (tail pascals)尚未找到 WHNF。我们已经在尝试了,所以<<loop>>.

(抱歉用文字把它拼出来,但我真的必须在脑海中像这样跟踪它才能第一次理解它)。

Way out?

根据我的定义,似乎所有定义都是正确的、数据流方面的。现在循环看起来很简单,因为评估器无法确定生成的结构是否是有限的。我找不到一种方法来保证“它是无限的”。

我觉得我需要一些惰性匹配的逆向:一些惰性返回,我可以告诉评估者 WHNF 的结果为(:),但是稍后您仍然需要调用这个 thunk 来了解其中的内容。

它仍然感觉像是一个固定点,但我还没有设法以一种有效的方式表达。


这是一个懒惰的版本zipWith这使得你的例子富有成效。它假设第二个列表至少与第一个列表一样长,但不强制这样做。

zipWith' :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith' f (i : is) ~(j : js) = f i j : zipWith' f is js

-- equivalently --

zipWith' f (i : is) jjs = f i (head j) : zipWith' f is (tail js)

看看我们要定义的矩阵:

matrix =
  [1,1,1,1,1,1,1...
  [1,/-------------
  [1,|
  [1,|  remainder
  [1,|
  ...

矩阵和余数之间有一个简单的关系,它描述了这样一个事实:余数中的每个条目都是通过将其左侧的条目与其上方的条目相加而获得的:对不包括第一行的矩阵求和,然后将没有第一列的矩阵。

remainder = (zipWith . zipWith) (+) (tail matrix) (map tail matrix)

从那里,我们可以对其余部分应用修补/填充函数,以填充第一行和第一列,并编辑任何元素。这些修改将通过递归发生反馈matrix。这导致以下广义定义pascals:

-- parameterized by the patch
-- and the operation to generate each entry from its older neighbors
pascals_ :: ([[a]] -> [[a]]) -> (a -> a -> a) -> [[a]]
pascals_ pad (+) = self where
  self = pad ((zipWith . zipWith) (+) (tail self) (map tail self))

例如,最简单的填充函数是用初始行和列来完成矩阵。

rowCol :: [a] -> [a] -> [[a]] -> [[a]]
rowCol row col remainder = row : zipWith' (:) col remainder

这里我们必须小心,不要在剩余部分中偷懒,因为我们正在定义它,因此使用zipWith'上面定义的。换句话说,我们必须确保如果我们通过undefined to rowCol row col我们仍然可以看到可以生成矩阵其余部分的初始值。

Now pascals可以定义如下。

pascals :: [[Integer]]
pascals = pascals_ (rowCol (repeat 1) (repeat 1)) (+)

截断无限矩阵的助手:

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

双递归定义列表的双无限列表 的相关文章

随机推荐

  • 如何修改请求的http header; C# 中的网络参考

    我正在创建一个使用 Web 服务的 NET 应用程序 我需要在对该 Web 服务的请求中将连接 http 标头设置为 关闭 我已经在谷歌上搜索了一天 但没有找到任何有用的东西 我最大的努力是下面的代码 它尝试重写 GetWebRequest
  • 开关与切换

    我正在尝试决定是否使用开关或切换来设置闹钟 我是我的 Android 应用程序 对 android 相当陌生 不知道或不太理解框架工作的所有来龙去脉 选择通过切换开关触发警报 反之亦然 会有什么缺点 android框架中有可用的滑动切换吗
  • Visual Studio 命令栏“名称”

    在 Visual Studio 2010 中 您可以创建的唯一选项是 菜单栏 上 工具 下的命令栏 在某些情况下 我想知道如何将命令栏放置在标准栏上 或者在右键单击项目文件时找到 Example Microsoft VisualStudio
  • 如何递归调用 WriteJson?

    我使用 Json Net 当我序列化一个Department2对象和WriteJson 被调用我希望它被递归地调用每个Telephone2像我一样的物体ReadJson 我怎么做 using System using Newtonsoft
  • 使用完全外连接连接 pandas 中的两个数据帧

    我在 pandas 中有两个数据框 如下所示 EmpID 是两个数据帧中的主键 df first pd DataFrame 1 A 1000 2 B np NaN 3 np NaN 3000 4 D 8000 5 E 6000 column
  • 限制直接 API 网关调用,除非来自 CloudFront

    我们在 API 前面创建了一个 CloudFront 是否可以限制来自 CloudFront 之外的 API 调用 当前设置 调用者 gt API 网关端点 gt Lambda 调用者 gt CloudFront 端点 gt API 网关端
  • Android GCM 消息发送时间过长

    我在我的应用程序中使用 GCM 但遇到了问题 大多数时候我会立即收到消息 但有时消息会在 5 分钟后收到 一条接着一条 就像它们被困在路上一样 这是正常的吗 客户端手机上的GCM框架部分使用TCP连接在端口 5228 上 此连接用于推送通知
  • 检查一个数组是否是另一个数组的子集

    关于如何检查该列表是否是另一个列表的子集有什么想法吗 具体来说 我有 List
  • 这总是GDB调试程序的地址吗?

    我将缩小我的问题范围 对于同一程序 GDB 中的入口地址保持不变 即使在重新启动后 以及在重写源代码后 这是为什么 例如0x80483f4是起始地址 0x80483f4
  • 为什么纯Python不能完全编译? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 为什么纯Python不能完全编译 编译或解释是实现的特征 而不是语言的特征 那么 难道不应该存在一些完全预先编译为本机代码的 Pyth
  • PHP:从未调用过 __autoload 函数

    所以 我有xampp 我在 ZendServer 上测试了这段代码 结果相同 在 php exe a index php 之后我有这个 Interactive mode enabled Fatal error Class Main not
  • 如何连接到第一行

    我将使用一个具体但假设的例子 Each Order通常只有一个行项目 Orders OrderGUID OrderNumber FFB2 STL 7442 1 3EC6 MPT 9931 8A 行项目 LineItemGUID Order
  • CUDA 内核可以是虚拟函数吗?

    这个问题非常简单 但让我概述一下我的框架 我有一个抽象类AbstractScheme表示一种计算类型 方程的一种离散化 但这并不重要 每个实现都必须提供一个方法来返回方案名称 并且必须实现一个受保护的函数 即 CUDA 内核 基本抽象类提供
  • 如何更改导航栏标题中链接和导航丸中链接的文本颜色(在闪亮的应用程序中)?

    这是我的闪亮应用程序的编辑版本 library shiny library bslib ui lt tagList fluidPage titlePanel tags head tags style HTML navbar default
  • Grails,使用 withTransaction 插入大量数据会导致 OutOfMemoryError

    我正在使用 Grails 1 1 beta2 我需要将大量数据导入到我的 Grails 应用程序中 如果我重复实例化一个 grails 域类然后保存它 性能会慢得令人无法接受 以从电话簿导入人员为例 for each person in l
  • 将变量传递给 jenkins 管道中的 powershell 脚本块

    有没有办法在 powershell 脚本中使用 groovy 变量 我的示例脚本如下 node stage Invoke Installation def stdoutpowershell def serverName env fqdn w
  • Vuex 模块中的 Nuxtjs Axios CORS 错误

    我正在使用 Nuxtjs 和内置 Vuex 模块以及 Nuxtjs 的官方 axios 我试图从本地服务器获取数据 但它总是抛出 CORS 错误 因此 我对 Github 的公共端点进行了 API 调用 但没有成功 仅在控制台中收到 COR
  • 为什么通过 Putty 的 SSH 命令与通过 PHP 的 phpseclib 的 SSH 命令的工作方式不同?

    我正在编写一个脚本来自动从我的 Windows 开发 PC 部署到共享托管服务器 根据我是通过 Putty 还是 PHP 执行命令 我会得到不同的结果 两者都在我的电脑上运行 在 putty 中 当我通过 SSH 登录服务器时 我可以运行如
  • PHP 数组...空括号的含义是什么?

    我遇到了一些示例代码 如下所示 form submit annotate admin settings submit 为什么 submit 后面有一个空的括号 里面什么都没有 这意味着什么 谁能给我举个例子吗 通常 根据我的理解 这可能是错
  • 双递归定义列表的双无限列表

    Context 我问的是修补递归定义的列表 https stackoverflow com q 53988970 12274另一天 我现在尝试通过在 2D 列表 列表的列表 上操作来将其提升一个级别 我将使用帕斯卡三角形作为示例 例如这个美