通过 Reader 在 Haskell 中将 Monad.Memo 与环境相结合

Combine Monad.Memo with environment through Reader in Haskell

我正在做 open source library for POMDP. It uses Dynamic Programming 搜索其他具有成本函数的 2D space。

DP 在 master branch is based on MemoTrie for DP memoization which uses Haskell's lazy evaluation. And I need to have cost function to be tunable. I believe this will not play nicely with MemoTrie's lazy approach. I did a naive try 中实施,但正如预期的那样,完成所有测试需要数小时而不是数秒。

我决定使用 Monad.Memo is a way to go. Here is 的 monadic 方法进行第一次尝试,尽管不使用任何 Reader 上下文。但是现在我正在努力寻找正确的方法来为这个计算引入 Reader 上下文。

这个try我用约束引入了MonadReader。同时,我无法将 fq 和 fv 的相互递归描述为约束,只是试图仅记忆 fq。但即便如此,MonadReader 类型 class MonadMemo 的实现将 Reader 上下文作为键的一部分,并且由于我的上下文是一个函数,它几乎不可能是映射键的(一部分)。我只能解开 Writer monad 的内容:

:t fst . startEvalMemo . runWriterT $ fq 1 1 1

也无法进一步解开 Reader。

上次尝试 use ReaderT。但这不能编译给出像

这样的东西
• Occurs check: cannot construct the infinite type: v ~ [v]
    arising from a functional dependency between:
      constraint ‘MapLike
                    (containers-0.5.7.1:Data.Map.Base.Map (n, n, n) [v]) (n, n, n) v’
        arising from a use of ‘memol1’
      instance ‘MapLike (containers-0.5.7.1:Data.Map.Base.Map k v1) k v1’
        at <no location info>
• In the first argument of ‘for3’, namely ‘memol1’
  In the expression: for3 memol1 fv n
  In an equation for ‘v’: v = for3 memol1 fv n
• Relevant bindings include
    v :: n -> n -> ReaderT (DynamicEnv n v) (MemoQV n v) v
      (bound at src/Dynamic.hs:136:9)

所以我在 Haskell 中努力提高生产力,但在我学习它的过程中,像这样的问题花了我很长时间。很高兴听到您的任何建议!

在使用 ReaderT 的版本中,您的 Dynamic monad 在 MemoQV 周围多了一层。

在伪haskell中,有:

type R = ReaderT (DynamicEnv n r)
type L1 = MemoQ n r
type L2 = MemoV n r

之前的类型看起来像

   L1 (L2 Identity)
-- 0   1

我们从 "top" 开始对变压器进行编号,从 0 开始。 相比之下,Dynamic 现在看起来像

   R (L1 (L2 Identity))
-- 0  1   2

由于您在顶部插入了转换器 R,缓存转换器被移得更深。

这对 memol0memol1memol2 组合器很重要:memolN 使用第 N 层(因此预计具有匹配的类型),因此您需要在这些图层移动时相应地更新您的代码。

您使用memol1 here and memol0 here。当您分别将它们移动到 memol2memol1 时,文件会编译。