我的“重复排列”代码中的递归调用是否会累积而堵塞 RAM?

2023-12-03

一些背景知识:

我是一名业余程序员,几个月前,在学习了一段时间的 Mathematica 编程(我的第一语言)之后,我利用业余时间学习了 Haskell。我目前正在阅读 Will Kurt 所著的第二本 Haskell 书,但要让自己对 Haskell 代码感到满意还有很长的路要走。到目前为止,Codeabbey 一直是我进行实验和学习的平台。

我编写了一段代码来生成给定数字的排列,处理可能的重复数字,因此对于 588,它将在内部生成 588、858 和 885。

但是,因为我想扩展到相当大的输入数字(认为可能甚至有一百位数字长),所以我不想输出整个列表,然后对其执行计算,而是当场检查生成的每个数字对于某个属性,如果它有,那么我们就有一个获胜者,该数字作为输出返回,并且无需遍历庞大列表的其余部分。如果不幸的是没有找到所需的数字,并且我们未能成功地完成所有可能的排列,它会输出“0”。

我还选择将其设为命令行程序,通过 gnu parallel 向其提供值,以加快工作速度。

所以这是代码

import System.Environment

import Data.List 

toDigits :: Integer -> [Integer]
toDigits n = map (\n -> read [n]) (show n)

fromDigits :: Integral a => [a] -> Integer
fromDigits list = fromDigitsHelperFunction list 0

fromDigitsHelperFunction :: Integral a => [a] -> Integer -> Integer
fromDigitsHelperFunction [] acc = acc
fromDigitsHelperFunction (x:[]) acc = (fromIntegral x) + acc
fromDigitsHelperFunction digits@(x:xs) acc = fromDigitsHelperFunction xs (acc + ((fromIntegral x) * 10 ^((length digits) - 1 )))

testPermutationsWithRepetition :: ([Integer],Int,[Int],[(Int,Integer)]) -> [Integer]
testPermutationsWithRepetition (digits, index, rotationMap, registeredPositions)
   | index == 0 && rotationMap !! index == 0                                    = [0,0,0] --finish state (no more recursion). Nothing more to do
   | index == digitsLength - 1 && beautyCheck (fromDigits digits)           = digits
   | index == digitsLength - 1                                                  = testPermutationsWithRepetition (digits, index-1, rotationMap, registeredPositions)
   | not ((index,digits!!index) `elem` registeredPositions)                     = testPermutationsWithRepetition (digits, index+1, rotationMap, (index,digits!!index):registeredPositions)
   | rotationMap!!index == 0                                                    = testPermutationsWithRepetition (digits, index-1, restoredRotMap, restoredRegPositions)
   | rotationMap!!index > 0 && (index,digits!!index) `elem` registeredPositions = testPermutationsWithRepetition (shiftLDigits, index, subtractRot, registeredPositions)
   where digitsLength = length digits
         shiftLDigits = (fst splitDigits) ++ (tail $ snd splitDigits) ++ [head $ snd splitDigits]
         splitDigits = splitAt index digits
         restoredRotMap = (fst splitRotMap) ++ [digitsLength - index] ++ (tail $ snd splitRotMap)
         splitRotMap = splitAt index rotationMap
         restoredRegPositions = filter (\pos -> fst pos < index) registeredPositions  --clear everything below the parent index
         subtractRot = (fst splitRotMap) ++ [(head $ snd splitRotMap) - 1] ++ (tail $ snd splitRotMap)


--Frontend function for testing permutations by inputting a single parameter (the number in digit form)
testPermsWithRep :: [Integer] -> [Integer]
testPermsWithRep digits = testPermutationsWithRepetition (digits, 0, [length $ digits, (length $ digits) -1 .. 1], [])

main :: IO ()
main = do
   args <- getArgs
   let number = read (head args) :: Integer
   let checkResult = fromDigits $ testPermsWithRep $ toDigits number
   print checkResult

这实际上是一个顺序过程,其中一个索引变量指向数字列表上的某个数字,并根据我的规则对该列表执行递归调用。这些函数通过数字列表跟踪迄今为止在某些位置访问过的数字的进度(以避免重复遵循已经访问过的路径,直到到达最后一个数字(索引==长度-1)。如果我们到达那里的数字通过了美丽检查,它以产生的数字退出。

现在,在 Mathematica(或者我猜任何命令式语言)中,我可能会使用 While 循环和 Cases 进行检查,并通过程序的逻辑来实现这一点,无论计算需要多长时间(生成排列并检查它们是否有效性)它将需要适量的内存,足以真正保存“registeredPositions”列表(您可以将其称为特定位置中访问过的数字的记录,因此当我们深入索引但被清理时,它是一个变量列表当我们向后移动时向上)。然而在这种情况下,递归调用就像看起来一样堆积起来,整个事情就像一个fork炸弹,对于足够大的数字(例如27777772222222222222222223333)并最终崩溃。这种行为是否可以在 Haskell 中以不同的方式处理,或者是否没有办法避免递归和内存占用?

我真的很喜欢 Haskell,因为这些程序具有逻辑意义,但我也想将它用于像性能(和资源)很重要的情况。

作为旁注,我兄弟指出了这一点通过重复数字打印所有排列的算法在 C 中,速度相当快(虽然只生成一个列表),最重要的是具有最小的内存占用,尽管我可以看出其中还使用了递归。除此之外,我对 C 毫无头绪,而且我想坚持使用 Haskell,如果它最终能做我想做的事的话。

欢迎任何帮助。祝你有美好的一天!

编辑: 根据 Soleil 的建议,我使用评论中提供的附加信息更新我的帖子。具体来说:

  1. 使用“ghcchecking_program.hs”编译后,我使用“./checkingprogram 27777772222222222222222223333”运行该程序。在具有 4GB RAM 的 i5 3470 上,它运行大约 10 分钟,然后因分段错误而退出。在我兄弟的 32GB 机器上,他让它运行直到占用 20GB RAM。我想不需要再进一步了。我的测试是通过 Win10 WSL 在 Ubuntu 上进行的。他的是裸Linux

  2. testPermsWithRep 只是 testPermutationsWithRepetition 的前端,因此我只能提供数字,而 testPermsWithRep 创建初始参数并使用这些参数调用 testPermutationsWithRepetition。它准确地输出 testPermutationsWithRepetition 的输出,要么是通过测试的数字(以数字形式),要么是 [0,0,0]。现在进行测试,beautyCheck 函数只是测试该数字的个位数除数,返回 True 或 False。我没有包括它,因为它确实无关紧要。它甚至可能只是一个“大于 x 数”的测试。

举个例子,调用“testPermsWithRep [2,6,7,3]”将调用“testPermutationsWithRepetition ([2,6,7,3], 0, [4,3,2,1],[])”等等从该函数中出来, testPermsWithRep 也会返回它。


您的程序的性能问题与递归无关。相反,您似乎在旋转图中遇到了部分评估的惰性数据结构的累积。如果您使用,您的程序将在恒定内存中运行deepseq包以充分强制评估restoredRotMap:

-- Install the `deepseq` package and add this import
import Control.DeepSeq

-- And then change this one case
... | rotationMap!!index == 0 = restoredRotMap `deepseq`
      testPermutationsWithRepetition (digits, index-1, restoredRotMap, restoredRegPositions)

编译为ghc -O2并使用beautyMap _ = False,它以大约 6 兆的固定驻留内存使用量运行。

其他一些绩效目标:

  • 您可能想要更换大部分Integer类型与Int,因为这样会更快。我想你只需要Integer对于输入toDigits和输出fromDigits,其他一切都可以Int,因为它都是索引和数字。
  • 更大的胜利将是用更好的数据结构替换您的轮换图和注册位置。如果您发现自己拼接了很多列表listpart1 ++ [x] ++ listpart2调用,这将带来巨大的性能成本,并且线性查找(!!)也没有帮助。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

我的“重复排列”代码中的递归调用是否会累积而堵塞 RAM? 的相关文章

  • 解析 PHOAS 表达式

    我想我理解 PHOAS 参数化高阶抽象语法 我明白了如何漂亮地打印一个表达式 参见http www reddit com r haskell comments 1mo59h phoas for free by edward kmett cc
  • 什么是阴谋地狱?

    在阅读有关 阴谋地狱 的内容时 我有点困惑 因为这个词的含义太多了 我猜最初 Cabal Hell 指的是钻石依赖问题 该问题是通过限制构建计划在每个构建计划中只有任何包的单个版本来解决的 一个包的两个不同版本不能存在于单个构建计划中 正如
  • 嵌套在其他 monad 中的 IO 操作未执行

    我有一个 foobar IO ParseResult String String ParseResult 是一个在这里定义的 monad https hackage haskell org package haskell src exts
  • 如何处理在组合下发生变化的类型?

    我最近读了一篇非常有趣的论文单调性类型 https infoscience epfl ch record 231867 files monotonicity types pdf其中描述了一种新的 HM 语言 该语言可以跟踪操作之间的单调性
  • 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 - 翻转具有两个参数的类型类的参数

    我有一个多参数类型类 它提供了一个可以交换其参数的函数 class Swappable a b where swappable a gt b gt Bool So if a and b form Swappable a b then b a
  • 数据类型变体之间的转换

    假设我想创建一种数据类型的两种变体 一种具有特定的构造函数 另一种没有它 否则它们是相同的 我想出了这个 LANGUAGE KindSignatures LANGUAGE DataKinds LANGUAGE GADTs data Foo
  • Haskell 中的所有图形和 Web 库是如何实现的?

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

    我正在尝试弄清楚如何执行以下操作 假设您正在开发直流电机的控制器 您希望让它以用户设置的特定速度旋转 def set point ref sp 90 while true let curr read speed controller set
  • 计算出类型索引的自由 monad 的细节

    我一直在使用免费的 monad 来构建 DSL 作为语言的一部分 有一个input命令 目标是在类型级别反映输入原语期望的类型 以提高安全性 例如 我希望能够编写以下程序 concat Action String String concat
  • `arr fst` 是如何自然变换的?

    I asked 这个问题 https stackoverflow com q 62733726 11143763不久以前 这是关于以下箭头定律 arr fst first f f arr fst Category k gt k b c gt
  • 加快 GHC 中的编译速度

    除了 O0 这可以加快编译时间吗 如果生成的程序未被优化也没关系 实际上我只想经常快速地对大型 haskell 包进行类型检查 Flag fno code极大地加快了编译速度 但无法使用它 因为该程序使用了 TemplateHaskell
  • 在类型级别未定义

    通常 当我使用 Haskell 代码时 我会使用类型注释将内容存根并undefined foo String gt Int foo undefined 是否有类型级别的 未定义 我可以以类似的方式使用 理想情况下 与某种注释结合使用 typ
  • 了解函数类型

    我在尝试理解 Haskell 如何确定函数类型时感到有点困惑 这是一个例子 boolFcn x y x 3 y 4 当我检查上述函数的类型时 它给出了结果 Num a1 Num a Eq a1 Eq a gt a gt a1 gt Bool
  • 在 Haskell 中使用 Maybe 类型

    我正在尝试利用 Haskell 中的 Maybe 类型 我有一个查找返回 Maybe 的键 值元组 如何访问 Maybe 包装的数据 例如 我想将 Maybe 包含的整数与另一个整数相加 或者 您可以进行模式匹配 case maybeVal
  • 当 Haskell 持久库中需要“Key”时,如何通过“Int”获取实体?

    我将持久性 orm 与 scotty Web 框架一起使用 我想通过 id 从 db 获取值 这些是来自 GET 请求的 有 get 函数接受 Key Entity 变量并返回 Maybe Entity 我使用以下代码从数据库获取值 k l
  • 为什么阴谋集团重新安装“总是危险的”?

    使用 Cabal 重新安装软件包时 通常会看到以下警告 警告 请注意 重新安装总是很危险的 无论如何继续 此消息背后的一些原因是什么 目前 重新安装软件包意味着破坏性地覆盖已安装的软件包 如果旧包对系统有任何反向依赖性 它们将不再工作 为了
  • Haskell 程序查找列表中元素的位置

    我需要编写一个函数来查找列表中一个特定元素的位置 我是这样写的 findPos list elt list 1 head list elt 0 otherwise 1 findPos tail list elt 但是如果列表中元素重复怎么办
  • 我必须实现 Applicative 和 Functor 来实现 Monad

    我正在尝试实现一个 Monad 实例 作为一个更简单的示例 假设如下 data Maybee a Notheeng Juust a instance Monad Maybee where return x Juust x Notheeng
  • Haskell 中的纯函数是否有可能改变变量的本地副本?

    Haskell 中的纯函数是否有可能改变变量的本地副本 就像 clojure 中提到的那样函数式编程是一个骗局 http swannodette github io 2013 06 10 porting notchs minecraft d

随机推荐

  • Android:如何使用画布/绘制位图缩放位图以适合屏幕尺寸?

    我正在拍摄图像并使用画布将其绘制到屏幕上 我想根据屏幕尺寸缩放它 这是我尝试过的 但它切断了图像的一大块 DisplayMetrics metrics context getResources getDisplayMetrics int w
  • Sendkeys 在 android appium 驱动程序上失败

    我正在使用 appium 来自动化 Android 应用程序 在这种情况下 无法在以下情况下对文本字段执行 sendkeys 单击添加客户选项 新页面打开 我正在尝试在文本字段中输入值 我能够使用 xpath 找到页面上的文本字段 我可以单
  • spinner If Strings** == 不工作

    为什么这不起作用 if itemx Test number item 0 Log i Dropdown inside if us lo ans hold setText 0x 如果 itemx 是字符串并且它具有字符串 测试编号项目 0 我
  • 在 FSharp 中查找两个数组之间的差异

    我有两个数组 我想在第二个数组中查找不在第一个数组中的元素 我写了以下代码 let array0 A B C let array1 B D E let inZero letter array0 gt Array tryFind fun l
  • 使用 jsoup 解析 JavaScript

    In an HTML页面 我想选择 a 的值javascript多变的 下面是片段HTML page
  • AutoMapper 将 2 个表中的记录连接到单个 IEnumerable 视图模型中

    我有 2 张桌子 比如说T1 and T2 T1包含oID CID 日期 状态 and T2包含cID cName cURL 我为上面两个表设计了类 如下所示 T1 cs public class T1 public int oID get
  • PHP 中的枚举

    我知道 PHP 还没有原生枚举 但我已经习惯了 Java 世界中的它们 我很乐意使用枚举来提供 IDE 的自动完成功能可以理解的预定义值 常量可以解决问题 但是存在命名空间冲突问题 或者实际上because 它们是全球性的 数组不存在命名空
  • 在C#中发送TCP数据包

    我想在 C 中发送 TCP 数据包 带有自定义标头 构建此类数据包没有问题 并且我将数据存储在字节数组中 但是我怎样才能通过套接字发送这个数据包呢 我尝试过这样的事情 using Socket sock new Socket Address
  • 将附加组件集成到自定义 Firefox 版本中

    我正在制作一个自定义的 Firefox 版本 我想将我的附加组件 附加 SDK 集成到构建中 我更喜欢这样做 而不是直接与 Firefox 代码集成 实现这一目标的最佳方法是什么 我正在考虑将其放入 浏览器 扩展 目录 如果这是一个好主意
  • 查找大写字符然后添加空格

    我购买了 SQL World 城市 州数据库 在州数据库中 州名称被集中在一起 示例 北卡罗来纳州 或 南卡罗来纳州 SQL中有没有办法循环查找大写字符并添加空格 这样 北卡罗来纳州 就变成了 北卡罗来纳州 创建这个函数 if object
  • java 8 中箭头运算符内部如何工作? [复制]

    这个问题在这里已经有答案了 我知道箭头的左侧有参数 箭头的右侧是参数所在的函数 但是 我想知道java 8如何映射左侧和右侧并转换为函数 那里会发生什么 我在哪里可以找到信息 当你有一个 gt javac 编译器添加一个包含代码内容的静态方
  • 如何在 React 中下载图像?

    我想尝试通过单击按钮来下载图像 但是当我单击按钮时 它不是下载图像 而是直接打开图像 但是我想下载图片 那么在React中如何下载图片呢 a href https timesofindia indiatimes com thumb msid
  • 如何使用 python pyhs2 连接到 hive?

    我正在尝试使用访问配置单元pyhs2 我尝试了以下代码 示例 py import pyhs2 conn pyhs2 connect host localhost port 10000 authMechanism None user None
  • Shibboleth 可以与 Windows Azure 访问控制服务集成吗?

    我们的两个高等教育客户使用 Shibboleth 进行 SSO 我对 Shib 的经验为零 并且没有可供测试的实例 最终 我们希望将 Shib SSO 与 Windows Azure MVC Web 角色中的这些客户端集成 所以我的问题是
  • 检测数组 vb.net 2005 上重复数字的最快方法

    我有这个项目 让用户输入从 1 到 50 的 5 个不同的数字 但我想在保存到数据库之前验证它 我将是 5 个唯一的数字 最好和最快的方法是什么 您可以使用哈希集 T 的 检查这个 Dim numbers As IEnumerable Of
  • 如何更改面板滚动条的背景颜色?

    因此 我正在为我的应用程序制作一个深色模式选项 并且我希望滚动条的背景颜色也改变颜色 这样它就不会看起来不合适 我试图寻找解决方案 但到目前为止我只找到了控件中滚动条的代码 但我需要更改面板的滚动条 有人知道该怎么做吗 预先非常感谢 当我开
  • 如何将 SecureString 转换为 System.String?

    关于通过创建 System String 来取消 SecureString 的所有保留意见aside 如何做呢 如何将普通的 System Security SecureString 转换为 System String 我相信许多熟悉 Se
  • Cassandra 与日志记录活动

    我将卡桑德拉与昆德拉一起使用 我的问题很简单 有什么方法可以记录所有查询 请求到 Cassandra 吗 我想知道服务器站点上到底发生了什么 Regards Tom 为 org apache cassandra thrift Cassand
  • 在服务中处理 $http 响应

    我最近发布了我面临的问题的详细描述here在这样 因为我无法发送实际的 http请求时 我使用超时来模拟异步行为 在 Gloopy 的帮助下 从我的模型到视图的数据绑定工作正常 现在 当我使用 http代替 timeout 本地测试 我可以
  • 我的“重复排列”代码中的递归调用是否会累积而堵塞 RAM?

    一些背景知识 我是一名业余程序员 几个月前 在学习了一段时间的 Mathematica 编程 我的第一语言 之后 我利用业余时间学习了 Haskell 我目前正在阅读 Will Kurt 所著的第二本 Haskell 书 但要让自己对 Ha