测试Monadic代码

anj*_*ruu 10 monads haskell

我正在通过Brent YorgeyHaskell课程学习Haskell .我刚刚到达monad部分,虽然我认为我(最后)对如何使用monad有一个很好的把握,但我不明白如何测试使用它们的代码.

本节的练习是编写一个(简化的)风险模拟,它需要大量使用Rand StdGenmonad.特别是,我们必须编写以下函数:

type Army = Int

data Battlefield = Battlefield { attackers :: Army, defenders :: Army }

battle :: Battlefield -> Rand StdGen Battlefield
Run Code Online (Sandbox Code Playgroud)

这需要一个初始的战场,并模拟这场战斗将如何进行.

我有一个实现,但我不明白如何测试它.我无法"获取" Rand StdGen Battlefield返回的内部值battle,因此我无法在GHCI解释器中打印出来,这就是我到目前为止测试代码的方式.我也无法弄清楚如何在Haskell主函数或其他东西中打印战斗结果.人们如何测试这些功能?

Ben*_*son 10

您可以使用evalRand和朋友这样的函数"获取"随机计算的结果.evalRand采取'开始' RandomGen并确定性地运行monadic计算.


这是我挥手的,非严格的解释evalRand:

monad和命令式编程之间的区别之一是monad是计算的表示,而不是计算本身.换句话说,当Haskell计算一个像a >>= b >>= c(或等效do符号)这样的表达式时,它只是将乐高积木放在一起,可以这么说 - 直到你使用像这样的函数执行 monad 才能进行计算evalRand.

有关更简单的示例,请考虑将功能组合在一起..为您提供一个函数,该函数表示由它组成的两个函数执行的计算.实际使用参数调用函数时,只能从该计算中获得返回值.

这就是为什么标准库中的许多monad(除了IO由运行时系统执行的)提供了一个"陷阱门"功能evalRand.这就是你实际使用你在monadic代码中定义的计算的方式.

  • 这是一种思考很多monad的有用方法,但它对于monad来说并非如此.列表monad不会推迟计算,直到您调用"陷阱门"功能(除了由于懒惰).只有monad提供对某种环境的隐式访问,这种环境必然以你描述的方式工作,这是因为例如`Rand StdGen Int`代表一个"概率整数",它需要提供一个`StdGen`来选择一个具体的`Int`来自它可能的所有值. (4认同)