【问题标题】:StateT and non-determinism monad: a simple exampleStateT 和非确定性单子:一个简单的例子
【发布时间】:2014-12-19 18:59:37
【问题描述】:

作为学习如何使用 StateT 和 nondeterminism monad 的一部分,我想编写一个函数,使用它们来枚举整数的分区(同时允许重用整数)。例如,传递4 的参数应该导致[[1,1,1,1],[1,1,2],[2,2],[1,3],[4]] (唯一性无关紧要,我更关心的只是开始工作代码)。

(另外,我知道有一个用于生成分区的递归解决方案以及用于计算分区的动态编程和基于生成函数的解决方案 - 本练习的目的是构建一个结合了 StateT 和 [] 的最小工作示例.)

这是我的尝试,旨在处理小于或等于 5 的任何输入:

{-# LANGUAGE NoImplicitPrelude #-}
{-# OPTIONS_GHC -Wall #-}

import CorePrelude
import Control.Monad.State.Lazy

sumState :: StateT Int [] [Int]
sumState = do
  m <- lift [1..5]
  n <- get <* modify (-m+)
  case compare n 0 of
    LT -> mzero
    EQ -> return [m]
    GT -> fmap (n:) sumState

runner :: Int -> [([Int],Int)]
runner = runStateT sumState

我使用runStateT 而不是evalStateT 来帮助调试(查看最终状态值很有帮助)。就像我说的,我不太担心生成唯一分区,因为我首先想了解一起使用这两个 monad 的正确方法。

GHCi 中加载它并评估runner 4 会导致以下结果,我很困惑为什么上面的代码会产生这个输出。

[([4,3,2,1,1],-1),([4,3,2,1,2],-2),([4,3,2,1,3],-3),([4,3,2,1,4],-4),([4,3,2,1,5],-5),([4,3,2,1],-1),([4,3,2,2],-2),([4,3,2,3],-3),([4,3,2,4],-4),([4,3,2,5],-5),([4,3,1,1],-1),([4,3,1,2],-2),([4,3,1,3],-3),([4,3,1,4],-4),([4,3,1,5],-5),([4,3,1],-1),([4,3,2],-2),([4,3,3],-3),([4,3,4],-4),([4,3,5],-5),([4,2,1,1],-1),([4,2,1,2],-2),([4,2,1,3],-3),([4,2,1,4],-4),([4,2,1,5],-5),([4,2,1],-1),([4,2,2],-2),([4,2,3],-3),([4,2,4],-4),([4,2,5],-5),([4,1,1],-1),([4,1,2],-2),([4,1,3],-3),([4,1,4],-4),([4,1,5],-5),([4,1],-1),([4,2],-2),([4,3],-3),([4,4],-4),([4,5],-5)]

我做错了什么?结合 StateT 和 [] 以枚举分区的正确方法是什么?

【问题讨论】:

  • (-m+) 让我大吃一惊。那到底是什么
  • 我无法说出 (-m+) 实际在做什么,但我会解释我的意图:) 假设我们将参数 4 传递(即,runner 4GHCi)。这个想法是modify 会将当前状态(在第一遍中为4)减少一个数字 [1..5],它由 m 表示。然后我们测试新状态是 0 还是 ==0。如果0,我们将 m 添加到该特定分支中的分区(通过fmap (m:))并冲洗/重复,如果 ==0,我们在达到目标总和时简单地终止分支(通过return [m])在那个分支中。
  • @MathematicalOrchid 自然是(+)-m 的部分应用。虽然它的传统拼写是subtract m

标签: haskell state monads monad-transformers statet


【解决方案1】:

你只有两个小错误。第一个在这里:

n <- get <* modify (-m+)

在我们减去m 之前,这会得到n 的值。你几乎肯定想要

n <- modify (-m+) >> get

相反,或者

modify (-m+)
n <- get

如果你更喜欢那个拼写。另一个是您将当前状态放入列表中,而不是您在 GT 分支中添加的值:

GT -> fmap (n:) sumState

改成

GT -> fmap (m:) sumState

你是金子:

*Main> runner 4
[([1,1,1,1],0),([1,1,2],0),([1,2,1],0),([1,3],0),([2,1,1],0),([2,2],0),([3,1],0),([4],0)]

【讨论】:

  • 宾果游戏。 (第二个是我公认的愚蠢错误......)谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-31
  • 2021-12-02
  • 1970-01-01
相关资源
最近更新 更多