在 Haskell 中实现记忆功能

2024-04-02

我对 Haskell 相当陌生,我正在尝试实现一个基本的记忆功能,它使用Data.Map存储计算值。我的示例是欧拉项目问题 15,其中涉及计算 20x20 网格中从一个角到另一个角的可能路径数。

这是我到目前为止所拥有的。我还没有尝试编译,因为我知道它不会编译。下面我会解释一下。

import qualified Data.Map as Map

main = print getProblem15Value

getProblem15Value :: Integer
getProblem15Value = getNumberOfPaths 20 20

getNumberOfPaths :: Integer -> Integer -> Integer
getNumberOfPaths x y = memoize getNumberOfPaths' (x,y)
where getNumberOfPaths' mem (0,_) = 1
      getNumberOfPaths' mem (_,0) = 1
      getNumberOfPaths' mem (x,y) = (mem (x-1,y)) + (mem (x,y-1))

memoize :: ((a -> b) -> a -> b) -> a -> b
memoize func x = fst $ memoize' Map.Empty func x
    where memoize' map func' x' = case (Map.lookup x' map) of (Just y) -> (y, map)
                                                              Nothing -> (y', map'')
           where y' = func' mem x'
                 mem x'' = y''
                 (y'', map') = memoize' map func' x''
                 map'' = Map.insert x' y' map'

基本上,我的结构方式是memoize是一个组合器(根据我的理解)。记忆之所以有效,是因为memoize提供一个函数(在本例中getNumberOfPaths') 并带有一个函数来调用 (mem)用于递归,而不是getNumberOfPaths'调用自身,这将在第一次迭代后删除记忆。

我的实施memoize接受一个函数(在本例中getNumberOfPaths')和一个初始值(在本例中是一个元组(x,y)表示距网格另一个角的网格单元距离的数量)。它调用memoize'它具有相同的结构,但包含一个空的Map保存值,并返回一个包含返回值和新计算值的元组Map. memoize'进行映射查找并返回该值和原始映射(如果存在值)。如果不存在值,则返回计算值和新映射。

这就是我的算法崩溃的地方。为了计算新值,我调用func' (getNumberOfPaths') with mem and x'. mem只是返回y'', where y''包含在调用结果中memoize' again. memoize'还返回一个新的映射,然后我们向其中添加新值并用作memoize'.

这里的问题是该行(y'', map') = memoize' map func' x''应该在mem因为它依赖于x'',这是一个参数mem。我当然可以做到,但那样我就会失去map'value,我需要它,因为它包含来自中间计算的记忆值。不过我不想介绍Map返回值mem因为然后函数传递给memoize将不得不处理Map.

抱歉,如果这听起来令人困惑。很多超高阶函数的东西让我感到困惑。

我确信有办法做到这一点。我想要的是一个通用的memoize允许递归调用的函数与定义中完全相同getNumberOfPaths,其中计算逻辑不必确切关心记忆是如何完成的。


如果您的输入足够小,您可以做的一件事是将备忘录表分配为Array代替Map,包含提前的所有结果,但计算延迟:

import Data.Array ((!), array)

numPaths :: Integer -> Integer -> Integer
numPaths w h = get (w - 1) (h - 1)
  where

    table = array (0, w * h)
      [ (y * w + x, go x y)
      | y <- [0 .. h - 1]
      , x <- [0 .. w - 1]
      ]

    get x y = table ! fromInteger (y * w + x)

    go 0 _ = 1
    go _ 0 = 1
    go x y = get (x - 1) y + get x (y - 1)

如果您愿意,您还可以将其拆分为单独的函数:

numPaths w h = withTable w h go (w - 1) (h - 1)
  where
    go mem 0 _ = 1
    go mem _ 0 = 1
    go mem x y = mem (x - 1) y + mem x (y - 1)

withTable w h f = f'
  where
    f' = f get
    get x y = table ! fromInteger (y * w + x)
    table = makeTable w h f'

makeTable w h f = array (0, w * h)
  [ (y * w + x, f x y)
  | y <- [0 .. w - 1]
  , x <- [0 .. h - 1]
  ]

我不会剧透,但答案还有一个非递归公式。

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

在 Haskell 中实现记忆功能 的相关文章

  • 通过 Emacs 评估 ghci 或 Hugs 中的缓冲区

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

    我想将 Blueprint CSS 框架与 Yesod 一起使用 有没有最佳实践 因为 Yesod 使用 CSS 模板 所以在我看来我不能直接使用 css 文件 我必须将它们重命名为 lucius files 吗 如何将 CSS 添加到 d
  • 访问函数中的环境

    In main我可以读取我的配置文件 并将其提供为runReader somefunc myEnv正好 但somefunc不需要访问myEnv读者提供 链中的下一对也没有提供 需要 myEnv 中某些内容的函数是一个微小的叶函数 如何在不将
  • 使用 nix 在 Mac OS X 上由于“架构 x86_64 的未定义符号”而导致“堆栈构建”失败

    首先是错误消息 stack build Linking Users yuzhao stack setup exe cache x86 64 osx tmp Cabal simple mPHDZzAJ 2 2 0 1 ghc 8 4 4 cl
  • 如何让 Show 显示函数名称?

    作为一个让我熟悉 Haskell 的简单练习 在 Youtube 上闲逛并偶然进入美国倒计时游戏节目之后 我想为数字游戏制作一个求解器 你得到 6 个数字 需要将它们与 为了得到给定的结果 到目前为止我所得到的是非常脑死亡的 let ope
  • 在 Haskell 中增长数组

    我想在 Haskell 中实现以下 命令式 算法 给定一个序列对 e0 s0 e1 s1 e2 s2 en sn 其中 e 和 s 部分不一定是自然数不同的是 在每个时间步都会随机选择该序列的一个元素 例如 ei si 并根据 ei si
  • 将数据类型设置为 Kind * -> * 这不是函子

    布伦特 约尔吉类型分类百科全书 https www haskell org haskellwiki Typeclassopedia给出以下练习 举一个类型的例子 gt 不能将其制成 的实例Functor 不使用undefined 请告诉我什
  • Haskell 下划线与显式变量

    我已经学习 Haskell 几个星期了 我有一个关于下划线的使用的问题 作为函数参数 我认为用一个具体的例子来问我的问题会更好 假设我想定义一个函数 根据提供的索引提取列表的元素 是的 我意识到 已经是预先定义的 我可以定义该函数的两种方法
  • Haskell scala 互操作性

    我是 Scala 初学者 来自面向对象范式 在了解 Scala 的函数式编程部分时 我被引导到 Haskell 纯函数式编程语言 探索 SO 问题答案 我发现 Java Haskell 具有互操作性 我很想知道 Scala Haskell
  • 在 Haskell 中,为什么我必须在这段代码中使用美元符号?

    我仍在尝试破解这段代码 import Data Char groupsOf groupsOf n xs take n xs groupsOf n tail xs problem 8 x maximum map product groupsO
  • 搜索重写规则

    有什么办法可以浏览或搜索重写规则吗 当我使用像这样的标志时 ddump rule firings or ddump rule rewrites我只是得到了触发的规则的名称以及它引起的重写 但没有得到实际的规则本身 理想情况下 我想通过 GH
  • Haskell - 用防护罩替换外壳

    我想知道在这部分代码中是否可以用守卫替换 case 语句 firstFunction String gt Maybe MyType secondFunction MyType gt Integer myFunction String gt
  • 如何在 Haskell 中漂亮地打印表格?

    我想在 Haskell 中漂亮地打印一个类似表格的数据结构 列列表 例如 Table StrCol strings a bc c IntCol ints 1 30 2 DblCol doubles 2 0 4 5 3 2 应该渲染类似 st
  • 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
  • 你能识别 Haskell 程序中的无限列表吗? [复制]

    这个问题在这里已经有答案了 可能的重复 如何判断列表是否是无限的 https stackoverflow com questions 7371730 how to tell if a list is infinite 在Haskell中 你
  • Haskell:IORef 的性能

    我一直在尝试在 Haskell 中编码一个需要使用大量可变引用的算法 但与纯粹的惰性代码相比 它 也许并不奇怪 非常慢 考虑一个非常简单的例子 module Main where import Data IORef import Contr
  • 为什么 ZipList 不是 List 的默认应用实例

    我目前正在学习 Haskell 中的应用程序 如果我没记错的话 列表有两个不同的应用实例 List and ZipList 第二个被定义为包装列表值的新类型 这ZipList应用实例对我来说似乎更直观 这可能是一个愚蠢的问题 但有具体原因吗
  • 在 Haskell 中合并两个列表

    无法弄清楚如何合并两个列表通过以下方式在哈斯克尔 INPUT 1 2 3 4 5 11 12 13 14 OUTPUT 1 11 2 12 3 13 4 14 5 我想提出一个更懒的合并版本 merge ys ys merge x xs y
  • 如何在Haskell中实现词法分析器和解析器

    我在这里得到了这段代码 它是用Haskell结构的命令式编程语言编写的程序 所以问题是 我如何为这种语言实现词法分析器和解析器 该程序被定义为一系列语句有 6 种类型 goto write stop if goto 和 int int n

随机推荐

  • bash 中有 do-while 循环吗? [复制]

    这个问题在这里已经有答案了 有没有do whilebash 中循环 我知道如何编程while在 bash 中循环 while condition do body done 是否有类似的构造 但是对于do while循环 其中body至少执行
  • 从应用程序到服务的通信

    我想从我的 Android 应用程序到我的 Android 服务进行通信 我有两个选择 但我不知道该选择哪个 使用应用程序注册服务 使用 LocalBinder 从应用程序连接到服务 解决方案1 应用程序 public class MyAp
  • Apache Cordova/Visual Studio 2015 工具无法在 IOS 模拟器中启动应用程序

    我尝试在 IOS 模拟器上使用 MacInCloud 和 Remotebuild 测试我的应用程序 一切都运行良好 并且应用程序使用 Remotebuild 进行编译 Visual Studio 随后会显示状态 部署成功 当我在 Mac 上
  • 在 zip 中写入(修改或添加)文件

    我已按照中的说明进行操作这个线程 https stackoverflow com questions 13787318 java util zip replace a single zip file 使用其中的代码 我已经能够将文件添加到
  • 如何使 XMLHttpRequest 在 Firefox 上通过 HTTPS 工作?

    当我尝试通过 XMLHttpRequest 发送 HTTP GET 请求时 它适用于非安全 HTTP 但是当通过 HTTPS 发送时 不同的浏览器给出不同的结果 在火狐 3 0 2 上 GET 请求未到达 Web 服务器 在 IE 7 上
  • 将 Plotly 与 R 结合使用的悬停模式

    当使用 R 和 ggplot2 进行绘图时 有没有办法对悬停模式进行编码 目前 我的代码是 plot lt ggplot data aes var1 var2 text var3 geom point py ggplotly plot 我希
  • Soundcloud API - Access-Control-Allow-Origin 不允许来源

    作为后续通过永久链接而不是 trackid 播放播放列表或曲目 https stackoverflow com questions 19351797 play playlist or track by permalink not track
  • 导致git merge冲突的原因和情况有哪些?

    什么是 必要和充分的条件 和 或 所有案例或一些常见案例 这可能会导致git merge报告合并冲突 如何git merge判断一行或几行是否包含 合并冲突 例如 我有时会看到类似以下的情况 其中Part 1 or Part 2是空的 lt
  • 尝试使用 socket.io 时出现错误

    我目前正在使用 socket io swift 客户端 在 Iphone SE 上运行 这是快速代码 let socket SocketIOClient socketURL URL string http example com 4000
  • 更改 CodeBlocks 中的链接器顺序

    我在 DialogBlocks 5 03 中有一个项目 可以使用 mingw32 正常编译 但使用 CodeBlocks 13 12 显示此错误 F wxWidgets 3 0 0 lib gcc lib libwxmsw30u core
  • 如何计算圆上两点之间的弧角?

    给定一个已知圆心和圆上两点 即已知半径 的圆 如何确定圆上两点之间的最小圆弧角度 将中心到两点变成一对向量 然后推过去this http en wikipedia org wiki Vector 28geometry 29 Dot prod
  • 为什么Android Studio 1.0 rc会开始下载Android SDK而不检测是否存在?

    我已经在我的 Archlinux 盒子里安装了 Android Studio 1 0 rc 和 Android SDK 但是当我尝试创建一个新的Android应用程序时 AS会尝试直接从dl ssl google com下载另一组SDK 我
  • 什么情况下不会调用 C++ 析构函数?

    我知道我的析构函数是在堆栈的正常展开和抛出异常时调用的 但不是在调用 exit 时调用 还有其他情况我的析构函数不会被调用吗 SIGINT 或 SIGSEGV 等信号怎么样 我认为对于 SIGSEGV 它们不会被调用 但对于 SIGNINT
  • ld: -bundle 和 -bitcode_bundle 不能一起使用

    我正在建造llvm clang 3 7具有位码支持 fembed bitcode 由于错误 某些模块无法链接 ld bundle 和 bitcode bundle Xcode 设置 ENABLE BITCODE YES 不能一起使用 cla
  • 实际上使用 UIDatePickerModeCountDownTimer 作为计时器

    我只是想制作一个计时器 我想用UIDatePickerModeCountDownTimer的模式UIDatePicker 这样当用户只需在选择器中选择 15 分钟时 他们就会返回到一个屏幕 该屏幕在标签中显示 15 分钟的值 然后他们可以从
  • 具有多表继承的父类上的 Django post_save 信号

    在 Django 中 如果您有使用多表继承的模型 并且您在父类上为 post save 信号定义了一个接收器 那么当保存子类的实例时 是否会调用该接收器函数 借个例子来自另一个问题 https stackoverflow com quest
  • 在 R 中将完整年龄从字符转换为数字

    我有一个数据集 其中人们的完整年龄为 R 中的字符串 例如 10 年 8 个月 23 天 我需要将其转换为有意义的数字变量 我正在考虑将其转换为有多少天人的年龄 这很困难 因为月份有不同的天数 因此 最好的解决方案可能是创建一个双变量 将年
  • 如何检测android中的屏幕覆盖?

    在某些设备中 当屏幕覆盖应用程序正在运行时 单击 VPN 权限确定按钮时不会执行任何操作 所以我想检查屏幕覆盖应用程序是否正在运行 并创建 检测到屏幕覆盖 对话框 有没有办法在android中以编程方式检测屏幕覆盖 示例代码 public
  • CATALINA_OPTS 与 JAVA_OPTS - 有什么区别?

    我试图找出 Apache Tomcat 变量之间的区别 CATALINA OPTS and JAVA OPTS in SO http stackoverflow com并惊讶地发现这里还没有发布问题 答案 所以我想在发现差异后在这里分享 带
  • 在 Haskell 中实现记忆功能

    我对 Haskell 相当陌生 我正在尝试实现一个基本的记忆功能 它使用Data Map存储计算值 我的示例是欧拉项目问题 15 其中涉及计算 20x20 网格中从一个角到另一个角的可能路径数 这是我到目前为止所拥有的 我还没有尝试编译 因